[pLog-svn] r3689 - in plog/trunk: . class class/test class/test/PHPUnit class/test/PHPUnit/GUI class/test/tests class/test/tests/data class/test/tests/data/validator class/test/tests/net

oscar at devel.lifetype.net oscar at devel.lifetype.net
Wed Jul 5 14:32:16 GMT 2006


Author: oscar
Date: 2006-07-05 14:32:15 +0000 (Wed, 05 Jul 2006)
New Revision: 3689

Added:
   plog/trunk/class/test/
   plog/trunk/class/test/PHPUnit.php
   plog/trunk/class/test/PHPUnit/
   plog/trunk/class/test/PHPUnit/Assert.php
   plog/trunk/class/test/PHPUnit/GUI/
   plog/trunk/class/test/PHPUnit/GUI/Gtk.php
   plog/trunk/class/test/PHPUnit/GUI/HTML.php
   plog/trunk/class/test/PHPUnit/GUI/HTML.tpl
   plog/trunk/class/test/PHPUnit/GUI/SetupDecorator.php
   plog/trunk/class/test/PHPUnit/RepeatedTest.php
   plog/trunk/class/test/PHPUnit/Skeleton.php
   plog/trunk/class/test/PHPUnit/TestCase.php
   plog/trunk/class/test/PHPUnit/TestDecorator.php
   plog/trunk/class/test/PHPUnit/TestFailure.php
   plog/trunk/class/test/PHPUnit/TestListener.php
   plog/trunk/class/test/PHPUnit/TestResult.php
   plog/trunk/class/test/PHPUnit/TestSuite.php
   plog/trunk/class/test/testrunner.class.php
   plog/trunk/class/test/tests/
   plog/trunk/class/test/tests/data/
   plog/trunk/class/test/tests/data/validator/
   plog/trunk/class/test/tests/data/validator/integervalidator_test.class.php
   plog/trunk/class/test/tests/net/
   plog/trunk/class/test/tests/net/url_test.class.php
   plog/trunk/runtests.php
Log:
I have been meaning to do this for a while, but now it looks like a good time. It will take a while to provide unit tests
for all core classes, but at least this is a start. There is no need to get tests for all of them before LT 1.1 is released, but it would be great if we could write the tests for all those classes where a bug or an improvement is being done.


Added: plog/trunk/class/test/PHPUnit/Assert.php
===================================================================
--- plog/trunk/class/test/PHPUnit/Assert.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/Assert.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,426 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: Assert.php,v 1.29 2005/11/10 09:47:14 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+/**
+ * A set of assert methods.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit_Assert {
+    /**
+     * @var    boolean
+     * @access private
+     */
+    var $_looselyTyped = FALSE;
+
+    /**
+     * Asserts that a haystack contains a needle.
+     *
+     * @param  mixed
+     * @param  mixed
+     * @param  string
+     * @access public
+     * @since  Method available since Release 1.1.0
+     */
+    function assertContains($needle, $haystack, $message = '') {
+        if (is_string($needle) && is_string($haystack)) {
+            $this->assertTrue(strpos($haystack, $needle) !== FALSE, $message);
+        }
+
+        else if (is_array($haystack) && !is_object($needle)) {
+            $this->assertTrue(in_array($needle, $haystack), $message);
+        }
+
+        else {
+            $this->fail('Unsupported parameter passed to assertContains().');
+        }
+    }
+
+    /**
+     * Asserts that a haystack does not contain a needle.
+     *
+     * @param  mixed
+     * @param  mixed
+     * @param  string
+     * @access public
+     * @since  Method available since Release 1.1.0
+     */
+    function assertNotContains($needle, $haystack, $message = '') {
+        if (is_string($needle) && is_string($haystack)) {
+            $this->assertFalse(strpos($haystack, $needle) !== FALSE, $message);
+        }
+
+        else if (is_array($haystack) && !is_object($needle)) {
+            $this->assertFalse(in_array($needle, $haystack), $message);
+        }
+
+        else {
+            $this->fail('Unsupported parameter passed to assertNotContains().');
+        }
+    }
+
+    /**
+     * Asserts that two variables are equal.
+     *
+     * @param  mixed
+     * @param  mixed
+     * @param  string
+     * @param  mixed
+     * @access public
+     */
+    function assertEquals($expected, $actual, $message = '', $delta = 0) {
+        if ((is_array($actual)  && is_array($expected)) ||
+            (is_object($actual) && is_object($expected))) {
+            if (is_array($actual) && is_array($expected)) {
+                ksort($actual);
+                ksort($expected);
+            }
+
+            if ($this->_looselyTyped) {
+                $actual   = $this->_convertToString($actual);
+                $expected = $this->_convertToString($expected);
+            }
+
+            $actual   = serialize($actual);
+            $expected = serialize($expected);
+
+            $message = sprintf(
+              '%sexpected %s, actual %s',
+
+              !empty($message) ? $message . ' ' : '',
+              $expected,
+              $actual
+            );
+
+            if ($actual !== $expected) {
+                return $this->fail($message);
+            }
+        }
+
+        elseif (is_numeric($actual) && is_numeric($expected)) {
+            $message = sprintf(
+              '%sexpected %s%s, actual %s',
+
+              !empty($message) ? $message . ' ' : '',
+              $expected,
+              ($delta != 0) ? ('+/- ' . $delta) : '',
+              $actual
+            );
+
+            if (!($actual >= ($expected - $delta) && $actual <= ($expected + $delta))) {
+                return $this->fail($message);
+            }
+        }
+
+        else {
+            $message = sprintf(
+              '%sexpected %s, actual %s',
+
+              !empty($message) ? $message . ' ' : '',
+              $expected,
+              $actual
+            );
+
+            if ($actual !== $expected) {
+                return $this->fail($message);
+            }
+        }
+    }
+
+    /**
+     * Asserts that two variables reference the same object.
+     * This requires the Zend Engine 2 to work.
+     *
+     * @param  object
+     * @param  object
+     * @param  string
+     * @access public
+     * @deprecated
+     */
+    function assertSame($expected, $actual, $message = '') {
+        if (!version_compare(phpversion(), '5.0.0', '>=')) {
+            $this->fail('assertSame() only works with PHP >= 5.0.0.');
+        }
+
+        if ((is_object($expected) || is_null($expected)) &&
+            (is_object($actual)   || is_null($actual))) {
+            $message = sprintf(
+              '%sexpected two variables to reference the same object',
+
+              !empty($message) ? $message . ' ' : ''
+            );
+
+            if ($expected !== $actual) {
+                return $this->fail($message);
+            }
+        } else {
+            $this->fail('Unsupported parameter passed to assertSame().');
+        }
+    }
+
+    /**
+     * Asserts that two variables do not reference the same object.
+     * This requires the Zend Engine 2 to work.
+     *
+     * @param  object
+     * @param  object
+     * @param  string
+     * @access public
+     * @deprecated
+     */
+    function assertNotSame($expected, $actual, $message = '') {
+        if (!version_compare(phpversion(), '5.0.0', '>=')) {
+            $this->fail('assertNotSame() only works with PHP >= 5.0.0.');
+        }
+
+        if ((is_object($expected) || is_null($expected)) &&
+            (is_object($actual)   || is_null($actual))) {
+            $message = sprintf(
+              '%sexpected two variables to reference different objects',
+
+              !empty($message) ? $message . ' ' : ''
+            );
+
+            if ($expected === $actual) {
+                return $this->fail($message);
+            }
+        } else {
+            $this->fail('Unsupported parameter passed to assertNotSame().');
+        }
+    }
+
+    /**
+     * Asserts that a variable is not NULL.
+     *
+     * @param  mixed
+     * @param  string
+     * @access public
+     */
+    function assertNotNull($actual, $message = '') {
+        $message = sprintf(
+          '%sexpected NOT NULL, actual NULL',
+
+          !empty($message) ? $message . ' ' : ''
+        );
+
+        if (is_null($actual)) {
+            return $this->fail($message);
+        }
+    }
+
+    /**
+     * Asserts that a variable is NULL.
+     *
+     * @param  mixed
+     * @param  string
+     * @access public
+     */
+    function assertNull($actual, $message = '') {
+        $message = sprintf(
+          '%sexpected NULL, actual NOT NULL',
+
+          !empty($message) ? $message . ' ' : ''
+        );
+
+        if (!is_null($actual)) {
+            return $this->fail($message);
+        }
+    }
+
+    /**
+     * Asserts that a condition is true.
+     *
+     * @param  boolean
+     * @param  string
+     * @access public
+     */
+    function assertTrue($condition, $message = '') {
+        $message = sprintf(
+          '%sexpected TRUE, actual FALSE',
+
+          !empty($message) ? $message . ' ' : ''
+        );
+
+        if (!$condition) {
+            return $this->fail($message);
+        }
+    }
+
+    /**
+     * Asserts that a condition is false.
+     *
+     * @param  boolean
+     * @param  string
+     * @access public
+     */
+    function assertFalse($condition, $message = '') {
+        $message = sprintf(
+          '%sexpected FALSE, actual TRUE',
+
+          !empty($message) ? $message . ' ' : ''
+        );
+
+        if ($condition) {
+            return $this->fail($message);
+        }
+    }
+
+    /**
+     * Asserts that a string matches a given regular expression.
+     *
+     * @param  string
+     * @param  string
+     * @param  string
+     * @access public
+     */
+    function assertRegExp($pattern, $string, $message = '') {
+        $message = sprintf(
+          '%s"%s" does not match pattern "%s"',
+
+          !empty($message) ? $message . ' ' : '',
+          $string,
+          $pattern
+        );
+
+        if (!preg_match($pattern, $string)) {
+            return $this->fail($message);
+        }
+    }
+
+    /**
+     * Asserts that a string does not match a given regular expression.
+     *
+     * @param  string
+     * @param  string
+     * @param  string
+     * @access public
+     * @since  Method available since Release 1.1.0
+     */
+    function assertNotRegExp($pattern, $string, $message = '') {
+        $message = sprintf(
+          '%s"%s" matches pattern "%s"',
+
+          !empty($message) ? $message . ' ' : '',
+          $string,
+          $pattern
+        );
+
+        if (preg_match($pattern, $string)) {
+            return $this->fail($message);
+        }
+    }
+
+    /**
+     * Asserts that a variable is of a given type.
+     *
+     * @param  string          $expected
+     * @param  mixed           $actual
+     * @param  optional string $message
+     * @access public
+     */
+    function assertType($expected, $actual, $message = '') {
+        return $this->assertEquals(
+          $expected,
+          gettype($actual),
+          $message
+        );
+    }
+
+    /**
+     * Converts a value to a string.
+     *
+     * @param  mixed   $value
+     * @access private
+     */
+    function _convertToString($value) {
+        foreach ($value as $k => $v) {
+            if (is_array($v)) {
+                $value[$k] = $this->_convertToString($value[$k]);
+            } else {
+                settype($value[$k], 'string');
+            }
+        }
+
+        return $value;
+    }
+
+    /**
+     * @param  boolean $looselyTyped
+     * @access public
+     */
+    function setLooselyTyped($looselyTyped) {
+        if (is_bool($looselyTyped)) {
+            $this->_looselyTyped = $looselyTyped;
+        }
+    }
+
+    /**
+     * Fails a test with the given message.
+     *
+     * @param  string
+     * @access protected
+     * @abstract
+     */
+    function fail($message = '') { /* abstract */ }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/GUI/Gtk.php
===================================================================
--- plog/trunk/class/test/PHPUnit/GUI/Gtk.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/GUI/Gtk.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,740 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Scott Mattocks <scott at crisscott.com>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: Gtk.php,v 1.6 2005/11/10 09:47:15 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.2.0
+ */
+
+if (!function_exists('is_a')) {
+    require_once 'PHP/Compat/Function/is_a.php';
+}
+
+/**
+ * GTK GUI interface for PHPUnit.
+ *
+ * This class is a PHP port of junit.awtui.testrunner. Documentation
+ * for junit.awtui.testrunner can be found at
+ * http://junit.sourceforge.net
+ *
+ * Due to the limitations of PHP4 and PHP-Gtk, this class can not
+ * duplicate all of the functionality of the JUnit GUI. Some of the
+ * things this class cannot do include:
+ * - Reloading the class for each run
+ * - Stopping the test in progress
+ *
+ * To use simply intantiate the class and call main()
+ * $gtk =& new PHPUnit_GUI_Gtk;
+ * $gtk->main();
+ *
+ * Once the window has finished loading, you can enter the name of
+ * a class that has been loaded (include/require some where in your
+ * code, or you can pass the name of the file containing the class.
+ *
+ * You can also load classes using the SetupDecorator class.
+ * require_once 'PHPUnit/GUI/SetupDecorator.php';
+ * require_once 'PHPUnit/GUI/Gtk.php';
+ * $gui = new PHPUnit_GUI_SetupDecorator(new PHPUnit_GUI_Gtk());
+ * $gui->getSuitesFromDir('/path/to/test','.*\.php$',array('index.php','sql.php'));
+ * $gui->show();
+ *
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Scott Mattocks <scott at crisscott.com>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.2.0
+ * @todo       Allow file drop. (Gtk_FileDrop)
+ */
+class PHPUnit_GUI_Gtk {
+
+    /**
+     * The main gtk window
+     * @var object
+     */
+    var $gui;
+    /**
+     * The text entry that contains the name of the
+     * file that holds the test(s)/suite(s).
+     * @var object
+     */
+    var $suiteField;
+    /**
+     * The label that shows the number of tests that
+     * were run.
+     * @var object
+     */
+    var $numberOfRuns;
+    /**
+     * The label that shows the number of errors that
+     * were encountered.
+     * @var object
+     */
+    var $numberOfErrors;
+    /**
+     * The label that shows the number of failures
+     * that were encountered.
+     * @var object
+     */
+    var $numberOfFailures;
+    /**
+     * The label for reporting user messages.
+     * @var object
+     */
+    var $statusLine;
+    /**
+     * The text area for reporting messages from successful
+     * test runs. (not necessarily successful tests)
+     * @var object
+     */
+    var $reportArea;
+    /**
+     * The text area for reporting errors encountered when
+     * running tests.
+     * @var object
+     */
+    var $dumpArea;
+    /**
+     * The progress bar indicator. Shows the percentage of
+     * passed tests.
+     * @var object
+     */
+    var $progress;
+    /**
+     * A checkbox for the user to indicate whether or not they
+     * would like to see results from all tests or just failures.
+     * @object
+     */
+    var $showPassed;
+
+    /**
+     * Constructor.
+     *
+     * The constructor checks for the gtk extension and loads it
+     * if needed. Then it creates the GUI. The GUI is not shown
+     * nor is the main gtk loop started until main() is called.
+     *
+     * @access public
+     * @param  none
+     * @return void
+     */
+    function PHPUnit_GUI_Gtk()
+    {
+        // Check for php-gtk extension.
+        if (!extension_loaded('gtk')) {
+            dl( 'php_gtk.' . PHP_SHLIB_SUFFIX);
+        }
+
+        // Create the interface but don't start the loop
+        $this->_createUI();
+    }
+    /**
+     * Start the main gtk loop.
+     *
+     * main() first sets the default state of the showPassed
+     * check box. Next all widgets that are part of the GUI
+     * are shown. Finally the main gtk loop is started.
+     *
+     * @access public
+     * @param  boolean $showPassed
+     * @return void
+     */
+    function main($showPassed = true)
+    {
+        $this->showPassed->set_active($showPassed);
+        $this->gui->show_all();
+
+        gtk::main();
+    }
+    /**
+     * Create the user interface.
+     *
+     * The user interface is pretty simple. It consists of a
+     * menu, text entry, run button, some labels, a progress
+     * indicator, and a couple of areas for notification of
+     * any messages.
+     *
+     * @access private
+     * @param  none
+     * @return void
+     */
+    function _createUI()
+    {
+        // Create a window.
+        $window =& new GtkWindow;
+        $window->set_title('PHPUnit Gtk');
+        $window->set_usize(400, -1);
+
+        // Create the main box.
+        $mainBox =& new GtkVBox;
+        $window->add($mainBox);
+
+        // Start with the menu.
+        $mainBox->pack_start($this->_createMenu());
+
+        // Then add the suite field entry.
+        $mainBox->pack_start($this->_createSuiteEntry());
+
+        // Then add the report labels.
+        $mainBox->pack_start($this->_createReportLabels());
+
+        // Next add the progress bar.
+        $mainBox->pack_start($this->_createProgressBar());
+
+        // Then add the report area and the dump area.
+        $mainBox->pack_start($this->_createReportAreas());
+
+        // Finish off with the status line.
+        $mainBox->pack_start($this->_createStatusLine());
+
+        // Connect the destroy signal.
+        $window->connect_object('destroy', array('gtk', 'main_quit'));
+
+        // Assign the member.
+        $this->gui =& $window;
+    }
+    /**
+     * Create the menu.
+     *
+     * The menu is very simple. It an exit menu item, which exits
+     * the application, and an about menu item, which shows some
+     * basic information about the application itself.
+     *
+     * @access private
+     * @param  none
+     * @return &object The GtkMenuBar
+     */
+    function &_createMenu()
+    {
+        // Create the menu bar.
+        $menuBar =& new GtkMenuBar;
+
+        // Create the main (only) menu item.
+        $phpHeader =& new GtkMenuItem('PHPUnit');
+
+        // Add the menu item to the menu bar.
+        $menuBar->append($phpHeader);
+
+        // Create the PHPUnit menu.
+        $phpMenu =& new GtkMenu;
+
+        // Add the menu items
+        $about =& new GtkMenuItem('About...');
+        $about->connect('activate', array(&$this, 'about'));
+        $phpMenu->append($about);
+
+        $exit =& new GtkMenuItem('Exit');
+        $exit->connect_object('activate', array('gtk', 'main_quit'));
+        $phpMenu->append($exit);
+
+        // Complete the menu.
+        $phpHeader->set_submenu($phpMenu);
+
+        return $menuBar;
+    }
+    /**
+     * Create the suite entry and related widgets.
+     *
+     * The suite entry has some supporting components such as a
+     * label, the show passed check box and the run button. All
+     * of these items are packed into two nested boxes.
+     *
+     * @access private
+     * @param  none
+     * @return &object A box that contains all of the suite entry pieces.
+     */
+    function &_createSuiteEntry()
+    {
+        // Create the outermost box.
+        $outerBox         =& new GtkVBox;
+
+        // Create the suite label, box, and field.
+        $suiteLabel       =& new GtkLabel('Test class name:');
+        $suiteBox         =& new GtkHBox;
+        $this->suiteField =& new GtkEntry;
+        $this->suiteField->set_text($suiteName != NULL ? $suiteName : '');
+
+        // Create the button the user will use to start the test.
+        $runButton =& new GtkButton('Run');
+        $runButton->connect_object('clicked', array(&$this, 'run'));
+
+        // Create the check box that lets the user show only failures.
+        $this->showPassed =& new GtkCheckButton('Show passed tests');
+
+        // Add the components to their respective boxes.
+        $suiteLabel->set_alignment(0, 0);
+        $outerBox->pack_start($suiteLabel);
+        $outerBox->pack_start($suiteBox);
+        $outerBox->pack_start($this->showPassed);
+
+        $suiteBox->pack_start($this->suiteField);
+        $suiteBox->pack_start($runButton);
+
+        return $outerBox;
+    }
+
+    /**
+     * Create the labels that tell the user what has happened.
+     *
+     * There are three labels, one each for total runs, errors and
+     * failures. There is also one label for each of these that
+     * describes what the label is. It could be done with one label
+     * instead of two but that would make updates much harder.
+     *
+     * @access private
+     * @param  none
+     * @return &object A box containing the labels.
+     */
+    function &_createReportLabels()
+    {
+        // Create a box to hold everything.
+        $labelBox         =& new GtkHBox;
+
+        // Create the non-updated labels.
+        $numberOfRuns     =& new GtkLabel('Runs:');
+        $numberOfErrors   =& new GtkLabel('Errors:');
+        $numberOfFailures =& new GtkLabel('Failures:');
+
+        // Create the labels that will be updated.
+        // These are asssigned to members to make it easier to
+        // set their values later.
+        $this->numberOfRuns     =& new GtkLabel(0);
+        $this->numberOfErrors   =& new GtkLabel(0);
+        $this->numberOfFailures =& new GtkLabel(0);
+
+        // Pack everything in.
+        $labelBox->pack_start($numberOfRuns);
+        $labelBox->pack_start($this->numberOfRuns);
+        $labelBox->pack_start($numberOfErrors);
+        $labelBox->pack_start($this->numberOfErrors);
+        $labelBox->pack_start($numberOfFailures);
+        $labelBox->pack_start($this->numberOfFailures);
+
+        return $labelBox;
+    }
+
+    /**
+     * Create the success/failure indicator.
+     *
+     * A GtkProgressBar is used to visually indicate how many
+     * tests were successful compared to how many were not. The
+     * progress bar shows the percentage of success and will
+     * change from green to red if there are any failures.
+     *
+     * @access private
+     * @param  none
+     * @return &object The progress bar
+     */
+    function &_createProgressBar()
+    {
+        // Create the progress bar.
+        $this->progress =& new GtkProgressBar(new GtkAdjustment(0, 0, 1, .1, 1, 0));
+
+        // Set the progress bar to print the percentage.
+        $this->progress->set_show_text(true);
+
+        return $this->progress;
+    }
+
+    /**
+     * Create the report text areas.
+     *
+     * The report area consists of one text area for failures, one
+     * text area for errors and one label for identification purposes.
+     * All three widgets are packed into a box.
+     *
+     * @access private
+     * @param  none
+     * @return &object The box containing the report areas.
+     */
+    function &_createReportAreas()
+    {
+        // Create the containing box.
+        $reportBox =& new GtkVBox;
+
+        // Create the identification label
+        $reportLabel =& new GtkLabel('Errors and Failures:');
+        $reportLabel->set_alignment(0, 0);
+
+        // Create the scrolled windows for the text areas.
+        $reportScroll =& new GtkScrolledWindow;
+        $dumpScroll   =& new GtkScrolledWindow;
+
+        // Make the scroll areas big enough.
+        $reportScroll->set_usize(-1, 150);
+        $dumpScroll->set_usize(-1, 150);
+
+        // Only show the vertical scroll bar when needed.
+        // Never show the horizontal scroll bar.
+        $reportScroll->set_policy(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+        $dumpScroll->set_policy(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+
+        // Create the text areas.
+        $this->reportArea =& new GtkText;
+        $this->dumpArea =& new GtkText;
+
+        // Don't let words get broken.
+        $this->reportArea->set_word_wrap(true);
+        $this->dumpArea->set_word_wrap(true);
+
+        // Pack everything in.
+        $reportBox->pack_start($reportLabel);
+        $reportScroll->add($this->reportArea);
+        $reportBox->pack_start($reportScroll);
+        $dumpScroll->add($this->dumpArea);
+        $reportBox->pack_start($dumpScroll);
+
+        return $reportBox;
+    }
+
+    /**
+     * Create a status label.
+     *
+     * A status line at the bottom of the application is used
+     * to notify the user of non-test related messages such as
+     * failures loading a test suite.
+     *
+     * @access private
+     * @param  none
+     * @return &object The status label.
+     */
+    function &_createStatusLine()
+    {
+        // Create the status label.
+        $this->statusLine =& new GtkLabel('');
+        $this->statusLine->set_alignment(0, 0);
+
+        return $this->statusLine;
+    }
+
+    /**
+     * Show a popup with information about the application.
+     *
+     * The popup should show information about the version,
+     * the author, the license, where to get the latest
+     * version and a short description.
+     *
+     * @access public
+     * @param  none
+     * @return void
+     */
+    function about()
+    {
+        // Create the new window.
+        $about =& new GtkWindow;
+        $about->set_title('About PHPUnit GUI Gtk');
+        $about->set_usize(250, -1);
+
+        // Put two vboxes in the hbox.
+        $vBox =& new GtkVBox;
+        $about->add($vBox);
+
+        // Create the labels.
+        $version     =& new GtkLabel(" Version: 1.0");
+        $license     =& new GtkLabel(" License: PHP License v3.0");
+        $where       =& new GtkLabel(" Download from: http://pear.php.net/PHPUnit/");
+        $unitAuth    =& new GtkLabel(" PHPUnit Author: Sebastian Bergman");
+        $gtkAuth     =& new GtkLabel(" Gtk GUI Author: Scott Mattocks");
+
+        // Align everything to the left
+        $where->set_alignment(0, .5);
+        $version->set_alignment(0, .5);
+        $license->set_alignment(0, .5);
+        $gtkAuth->set_alignment(0, .5);
+        $unitAuth->set_alignment(0, .5);
+
+        // Pack everything into the vBox;
+        $vBox->pack_start($version);
+        $vBox->pack_start($license);
+        $vBox->pack_start($where);
+        $vBox->pack_start($unitAuth);
+        $vBox->pack_start($gtkAuth);
+
+        // Connect the destroy signal.
+        $about->connect('destroy', array('gtk', 'true'));
+
+        // Show the goods.
+        $about->show_all();
+    }
+
+    /**
+     * Load the test suite.
+     *
+     * This method tries to load test suite based on the user
+     * info. If the user passes the name of a tests suite, it
+     * is instantiated and a new object is returned. If the
+     * user passes a file that contains a test suite, the class
+     * is instantiated and a new object is returned. If the user
+     * passes a file that contains a test case, the test case is
+     * passed to a new test suite and the new suite object is
+     * returned.
+     *
+     * @access public
+     * @param  string  The file that contains a test case/suite or the classname.
+     * @return &object The new test suite.
+     */
+    function &loadTest(&$file)
+    {
+        // Check to see if a class name was given.
+        if (is_a($file, 'PHPUnit_TestSuite')) {
+            return $file;
+        } elseif (class_exists($file)) {
+            require_once 'PHPUnit/TestSuite.php';
+            return new PHPUnit_TestSuite($file);
+        }
+
+        // Check that the file exists.
+        if (!@is_readable($file)) {
+            $this->_showStatus('Cannot find file: ' . $file);
+            return false;
+        }
+
+        $this->_showStatus('Loading test suite...');
+
+        // Instantiate the class.
+        // If the path is /path/to/test/TestClass.php
+        // the class name should be test_TestClass
+        require_once $file;
+        $className = str_replace(DIRECTORY_SEPARATOR, '_', $file);
+        $className = substr($className, 0, strpos($className, '.'));
+
+        require_once 'PHPUnit/TestSuite.php';
+        return new PHPUnit_TestSuite($className);
+    }
+
+    /**
+     * Run the test suite.
+     *
+     * This method runs the test suite and updates the messages
+     * for the user. When finished it changes the status line
+     * to 'Test Complete'
+     *
+     * @access public
+     * @param  none
+     * @return void
+     */
+    function runTest()
+    {
+        // Notify the user that the test is running.
+        $this->_showStatus('Running Test...');
+
+        // Run the test.
+        $result = PHPUnit::run($this->suite);
+
+        // Update the labels.
+        $this->_setLabelValue($this->numberOfRuns,     $result->runCount());
+        $this->_setLabelValue($this->numberOfErrors,   $result->errorCount());
+        $this->_setLabelValue($this->numberOfFailures, $result->failureCount());
+
+        // Update the progress bar.
+        $this->_updateProgress($result->runCount(),
+                               $result->errorCount(),
+                               $result->failureCount()
+                               );
+
+        // Show the errors.
+        $this->_showFailures($result->errors(), $this->dumpArea);
+
+        // Show the messages from the tests.
+        if ($this->showPassed->get_active()) {
+            // Show failures and success.
+            $this->_showAll($result, $this->reportArea);
+        } else {
+            // Show only failures.
+            $this->_showFailures($result->failures(), $this->reportArea);
+        }
+
+        // Update the status message.
+        $this->_showStatus('Test complete');
+    }
+
+    /**
+     * Set the text of a label.
+     *
+     * Change the text of a given label.
+     *
+     * @access private
+     * @param  widget  &$label The label whose value is to be changed.
+     * @param  string  $value  The new text of the label.
+     * @return void
+     */
+    function _setLabelValue(&$label, $value)
+    {
+        $label->set_text($value);
+    }
+
+    /**
+     * The main work of the application.
+     *
+     * Load the test suite and then execute the tests.
+     *
+     * @access public
+     * @param  none
+     * @return void
+     */
+    function run()
+    {
+        // Load the test suite.
+        $this->suite =& $this->loadTest($this->suiteField->get_text());
+
+        // Check to make sure the suite was loaded properly.
+        if (!is_object($this->suite)) {
+            // Raise an error.
+            $this->_showStatus('Could not load test suite.');
+            return false;
+        }
+
+        // Run the tests.
+        $this->runTest();
+    }
+
+    /**
+     * Update the status message.
+     *
+     * @access private
+     * @param  string  $status The new message.
+     * @return void
+     */
+    function _showStatus($status)
+    {
+        $this->statusLine->set_text($status);
+    }
+
+    /**
+     * Alias for main()
+     *
+     * @see main
+     */
+    function show($showPassed = true)
+    {
+        $this->main($showPassed);
+    }
+
+    /**
+     * Add a suite to the tests.
+     *
+     * This method is require by SetupDecorator. It adds a
+     * suite to the the current set of suites.
+     *
+     * @access public
+     * @param  object $testSuite The suite to add.
+     * @return void
+     */
+    function addSuites($testSuite)
+    {
+        if (!is_array($testSuite)) {
+            settype($testSuite, 'array');
+        }
+
+        foreach ($testSuite as $suite) {
+
+            if (is_a($this->suite, 'PHPUnit_TestSuite')) {
+                $this->suite->addTestSuite($suite->getName());
+            } else {
+                $this->suite =& $this->loadTest($suite);
+            }
+
+            // Set the suite field.
+            $text = $this->suiteField->get_text();
+            if (empty($text)) {
+                $this->suiteField->set_text($this->suite->getName());
+            }
+        }
+    }
+
+    /**
+     * Show all test messages.
+     *
+     * @access private
+     * @param  object  The TestResult from the test suite.
+     * @return void
+     */
+    function _showAll(&$result)
+    {
+        // Clear the area first.
+        $this->reportArea->delete_text(0, -1);
+        $this->reportArea->insert_text($result->toString(), 0);
+    }
+
+    /**
+     * Show failure/error messages in the given text area.
+     *
+     * @access private
+     * @param  object  &$results The results of the test.
+     * @param  widget  &$area    The area to show the results in.
+     */
+    function _showFailures(&$results, &$area)
+    {
+        $area->delete_text(0, -1);
+        foreach (array_reverse($results, true) as $result) {
+            $area->insert_text($result->toString(), 0);
+        }
+    }
+
+    /**
+     * Update the progress indicator.
+     *
+     * @access private
+     * @param  integer $runs
+     * @param  integer $errors
+     * @param  integer $failures
+     * @return void
+     */
+    function _updateProgress($runs, $errors, $failures)
+    {
+        $percentage = 1 - (($errors + $failures) / $runs);
+        $this->progress->set_percentage($percentage);
+    }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/GUI/HTML.php
===================================================================
--- plog/trunk/class/test/PHPUnit/GUI/HTML.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/GUI/HTML.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,252 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Wolfram Kriesing <wolfram at kriesing.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: HTML.php,v 1.19 2005/11/10 09:47:15 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+/**
+ * HTML GUI.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Wolfram Kriesing <wolfram at kriesing.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit_GUI_HTML
+{
+    var $_suites = array();
+
+    /**
+    * the current implementation of PHPUnit is designed
+    * this way that adding a suite to another suite only
+    * grabs all the tests and adds them to the suite, so you
+    * have no chance to find out which test goes with which suite
+    * therefore you can simply pass an array of suites to this constructor here
+    *
+    * @param  array   The suites to be tested. If not given, then you might
+    *                 be using the SetupDecorator, which detects them automatically
+    *                 when calling getSuitesFromDir()
+    */
+    function PHPUnit_GUI_HTML($suites = array())
+    {
+        if (!is_array($suites)) {
+            $this->_suites = array($suites);
+        } else {
+            $this->_suites = $suites;
+        }
+    }
+
+    /**
+    * Add suites to the GUI
+    *
+    * @param  object  this should be an instance of PHPUnit_TestSuite
+    */
+    function addSuites($suites)
+    {
+        $this->_suites = array_merge($this->_suites,$suites);
+    }
+
+    /**
+    * this prints the HTML code straight out
+    *
+    */
+    function show()
+    {
+        $request    = $_REQUEST;
+        $showPassed = FALSE;
+        $submitted  = @$request['submitted'];
+
+        if ($submitted) {
+            $showPassed = @$request['showOK'] ? TRUE : FALSE;
+        }
+
+        $suiteResults = array();
+
+        foreach ($this->_suites as $aSuite) {
+            $aSuiteResult = array();
+
+            // remove the first directory's name from the test-suite name, since it
+            // mostly is something like 'tests' or alike
+            $removablePrefix = explode('_',$aSuite->getName());
+            $aSuiteResult['name'] = str_replace($removablePrefix[0].'_', '', $aSuite->getName());
+
+            if ($submitted && isset($request[$aSuiteResult['name']])) {
+                $result = PHPUnit::run($aSuite);
+
+                $aSuiteResult['counts']['run'] = $result->runCount();
+                $aSuiteResult['counts']['error'] = $result->errorCount();
+                $aSuiteResult['counts']['failure'] = $result->failureCount();
+
+                $aSuiteResult['results'] = $this->_prepareResult($result,$showPassed);
+
+                $per = 100/$result->runCount();
+                $failed = ($per*$result->errorCount())+($per*$result->failureCount());
+                $aSuiteResult['percent'] = round(100-$failed,2);
+            } else {
+                $aSuiteResult['addInfo'] = 'NOT EXECUTED';
+            }
+
+            $suiteResults[] = $aSuiteResult;
+        }
+
+        $final['name'] = 'OVERALL RESULT';
+        $final['counts'] = array();
+        $final['percent'] = 0;
+        $numExecutedTests = 0;
+
+        foreach ($suiteResults as $aSuiteResult) {
+            if (sizeof(@$aSuiteResult['counts'])) {
+                foreach ($aSuiteResult['counts'] as $key=>$aCount) {
+                    if (!isset($final['counts'][$key])) {
+                        $final['counts'][$key] = 0;
+                    }
+
+                    $final['counts'][$key] += $aCount;
+                }
+            }
+        }
+
+        if (isset($final['counts']['run'])) {
+            $per = 100/$final['counts']['run'];
+            $failed = ($per*$final['counts']['error'])+($per*$final['counts']['failure']);
+            $final['percent'] = round(100-$failed,2);
+        } else {
+            $final['percent'] = 0;
+        }
+
+        array_unshift($suiteResults,$final);
+
+        include 'PHPUnit/GUI/HTML.tpl';
+    }
+
+    function _prepareResult($result,$showPassed)
+    {
+        $ret = array();
+        $failures = $result->failures();
+
+        foreach($failures as $aFailure) {
+            $ret['failures'][] = $this->_prepareFailure($aFailure);
+        }
+
+        $errors = $result->errors();
+
+        foreach($errors as $aError) {
+            $ret['errors'][] = $this->_prepareErrors($aError);
+        }
+
+        if ($showPassed) {
+            $passed = $result->passedTests();
+
+            foreach($passed as $aPassed) {
+                $ret['passed'][] = $this->_preparePassedTests($aPassed);
+            }
+        }
+
+        return $ret;
+    }
+
+    function _prepareFailure($failure)
+    {
+        $test = $failure->failedTest();
+        $ret['testName'] = $test->getName();
+        $exception = $failure->thrownException();
+
+        // a serialized string starts with a 'character:decimal:{'
+        // if so we try to unserialize it
+        // this piece of the regular expression is for detecting a serialized
+        // type like 'a:3:' for an array with three element or an object i.e. 'O:12:"class":3'
+        $serialized = '(\w:\d+:(?:"[^"]+":\d+:)?\{.*\})';
+
+        // Spaces might make a diff, so we shall show them properly (since a
+        // user agent ignores them).
+        if (preg_match('/^(.*)expected ' . $serialized . ', actual ' . $serialized . '$/sU', $exception, $matches)) {
+            ob_start();
+            print_r(unserialize($matches[2]));
+            $ret['expected'] = htmlspecialchars($matches[1]) . "<pre>" . htmlspecialchars(rtrim(ob_get_contents())) . "</pre>";
+            // Improved compatibility, ob_clean() would be PHP >= 4.2.0 only.
+            ob_end_clean();
+
+            ob_start();
+            print_r(unserialize($matches[3]));
+            $ret['actual'] = htmlspecialchars($matches[1]) . "<pre>" . htmlspecialchars(rtrim(ob_get_contents())) . "</pre>";
+            ob_end_clean();
+        }
+
+        else if (preg_match('/^(.*)expected (.*), actual (.*)$/sU', $exception, $matches)) {
+            $ret['expected'] = nl2br(str_replace(" ", "&nbsp;", htmlspecialchars($matches[1] . $matches[2])));
+            $ret['actual'] = nl2br(str_replace(" ", "&nbsp;", htmlspecialchars($matches[1] . $matches[3])));
+        } else {
+            $ret['message'] = nl2br(str_replace(" ", "&nbsp;", htmlspecialchars($exception)));
+        }
+
+        return $ret;
+    }
+
+    function _preparePassedTests($passed)
+    {
+        $ret['testName'] = $passed->getName();
+        return $ret;
+    }
+
+    function _prepareError($error)
+    {
+        $ret['testName'] = $error->getName();
+        $ret['message'] = $error->toString();
+        return $ret;
+    }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/GUI/HTML.tpl
===================================================================
--- plog/trunk/class/test/PHPUnit/GUI/HTML.tpl	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/GUI/HTML.tpl	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,156 @@
+<html>
+    <head>
+        <STYLE type="text/css">
+
+            body, td {
+                background-color: lightgrey;
+            }
+
+            table.outline, outlineFailure {
+                background-color: black;
+                border-width: 1px;
+            }
+
+            td {
+                padding: 2px;
+            }
+
+            th {
+                text-align: left;
+                color: white;
+                background-color: black;
+            }
+
+            .success {
+                background-color: lightgreen;
+            }
+
+            .failure {
+                background-color: orange;
+            }
+            .info {
+                padding: 2px;
+                color: orange;
+            }
+
+        </STYLE>
+    </head>
+    <body>
+        <form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="post" name="optionsForm">
+            <table align="center" class="outline" width="70%">
+                <tr>
+                    <th colspan="10">
+                        Options
+                    </th>
+                </tr>
+                <tr>
+                    <td colspan="10">
+                        <input type="checkbox" onClick="unCheckAll()" name="allChecked">
+                        (un)check all
+                        &nbsp; &nbsp;
+                        show OK <input type="checkbox" name="showOK" <?php echo @$request['showOK']?'checked':''?>>
+                        &nbsp; &nbsp;
+                        <input type="submit" name="submitted" value="run tests">
+                    </td>
+                </tr>
+
+                <?php foreach($suiteResults as $aResult): ?>
+                    <tr>
+                        <th colspan="10">
+                            <input type="checkbox" name="<?php echo $aResult['name'] ?>" <?php echo @$request[$aResult['name']]?'checked':'' ?>>
+                            <?php echo $aResult['name'] ?>
+                            &nbsp;
+                            <?php if (isset($aResult['addInfo'])): ?>
+                                <font class="info"><?php echo @$aResult['addInfo'] ?></font>
+                            <?php endif ?>
+                        </th>
+                    </tr>
+
+                    <?php if(@$aResult['percent']): ?>
+                        <tr>
+                            <td colspan="10" nowrap="nowrap">
+                                <table style="width:100%; padding:2px;" cellspacing="0" cellspan="0" cellpadding="0">
+                                    <tr>
+                                        <td width="<?php echo $aResult['percent'] ?>%" class="success" align="center" style="padding:0;">
+                                            <?php echo $aResult['percent']?$aResult['percent'].'%':'' ?>
+                                        </td>
+                                        <td width="<?php echo 100-$aResult['percent'] ?>%" class="failure" align="center" style="padding:0;">
+                                            <?php echo (100-$aResult['percent'])?(100-$aResult['percent'].'%'):'' ?>
+                                        </td>
+                                    </tr>
+                                </table>
+                            </td>
+                        </tr>
+                    <?php endif ?>
+
+                    <?php if(@$aResult['counts']): ?>
+                        <tr>
+                            <td colspan="10">
+                                <?php foreach($aResult['counts'] as $aCount=>$value): ?>
+                                    <?php echo $aCount ?>s = <?php echo $value ?> &nbsp; &nbsp; &nbsp; &nbsp;
+                                <?php endforeach ?>
+                            </td>
+                        </tr>
+                    <?php endif ?>
+
+                    <?php if(isset($aResult['results']['failures']) && sizeof($aResult['results']['failures']))
+                        foreach($aResult['results']['failures'] as $aFailure): ?>
+                        <tr>
+                            <td class="failure"><?php echo $aFailure['testName'] ?></td>
+                            <td class="failure">
+                                <?php if(isset($aFailure['message']) && $aFailure['message']): ?>
+                                    <?php echo $aFailure['message'] ?>
+                                <?php else: ?>
+                                    <table class="outlineFailure">
+                                        <tr>
+                                            <td>expected</td>
+                                            <td><?php echo $aFailure['expected'] ?></td>
+                                        </tr>
+                                        <tr>
+                                            <td>actual</td>
+                                            <td><?php echo $aFailure['actual'] ?></td>
+                                        </tr>
+                                    </table>
+                                <?php endif ?>
+                            </td>
+                        </tr>
+                    <?php endforeach ?>
+
+                    <?php if(isset($aResult['results']['errors']) && sizeof($aResult['results']['errors']))
+                        foreach($aResult['results']['errors'] as $aError): ?>
+                        <tr>
+                            <td class="failure"><?php echo $aError['testName'] ?></td>
+                            <td class="failure">
+                                <?php echo $aError['message'] ?>
+                            </td>
+                        </tr>
+                    <?php endforeach ?>
+
+                    <?php if(isset($aResult['results']['passed']) && sizeof($aResult['results']['passed']))
+                        foreach($aResult['results']['passed'] as $aPassed): ?>
+                        <tr>
+                            <td class="success"><?php echo $aPassed['testName'] ?></td>
+                            <td class="success"><b>OK</b></td>
+                        </tr>
+                    <?php endforeach ?>
+
+                <?php endforeach ?>
+            </table>
+        </form>
+
+        <script>
+            var allSuiteNames = new Array();
+            <?php foreach($suiteResults as $aResult): ?>
+                allSuiteNames[allSuiteNames.length] = "<?php echo $aResult['name'] ?>";
+            <?php endforeach ?>
+            function unCheckAll()
+            {
+                _checked = document.optionsForm.allChecked.checked;
+                for (i=0;i<allSuiteNames.length;i++) {
+                    document.optionsForm[allSuiteNames[i]].checked = _checked;
+                }
+            }
+        </script>
+
+    </body>
+</html>

Added: plog/trunk/class/test/PHPUnit/GUI/SetupDecorator.php
===================================================================
--- plog/trunk/class/test/PHPUnit/GUI/SetupDecorator.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/GUI/SetupDecorator.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,209 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Wolfram Kriesing <wolfram at kriesing.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: SetupDecorator.php,v 1.15 2005/11/10 09:47:15 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+/**
+ * This decorator actually just adds the functionality to read the
+ * test-suite classes from a given directory and instanciate them
+ * automatically, use it as given in the example below.
+ *
+ * <code>
+ * <?php
+ * $gui = new PHPUnit_GUI_SetupDecorator(new PHPUnit_GUI_HTML());
+ * $gui->getSuitesFromDir('/path/to/dir/tests','.*\.php$',array('index.php','sql.php'));
+ * $gui->show();
+ * ?>
+ * </code>
+ *
+ * The example calls this class and tells it to:
+ *
+ *   - find all file under the directory /path/to/dir/tests
+ *   - for files, which end with '.php' (this is a piece of a regexp, that's why the . is escaped)
+ *   - and to exclude the files 'index.php' and 'sql.php'
+ *   - and include all the files that are left in the tests.
+ *
+ * Given that the path (the first parameter) ends with 'tests' it will be assumed
+ * that the classes are named tests_* where * is the directory plus the filename,
+ * according to PEAR standards.
+ *
+ * So that:
+ *
+ *   - 'testMe.php' in the dir 'tests' bill be assumed to contain a class tests_testMe
+ *   - '/moretests/aTest.php' should contain a class 'tests_moretests_aTest'
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Wolfram Kriesing <wolfram at kriesing.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit_GUI_SetupDecorator
+{
+    /**
+    *
+    *
+    */
+    function PHPUnit_GUI_SetupDecorator(&$gui)
+    {
+        $this->_gui = &$gui;
+    }
+
+    /**
+    *   just forwarding the action to the decorated class.
+    *
+    */
+    function show($showPassed=TRUE)
+    {
+        $this->_gui->show($showPassed);
+    }
+
+    /**
+    * Setup test suites that can be found in the given directory
+    * Using the second parameter you can also choose a subsets of the files found
+    * in the given directory. I.e. only all the files that contain '_UnitTest_',
+    * in order to do this simply call it like this:
+    * <code>getSuitesFromDir($dir,'.*_UnitTest_.*')</code>.
+    * There you can already see that the pattern is built for the use within a regular expression.
+    *
+    * @param  string  the directory where to search for test-suite files
+    * @param  string  the pattern (a regexp) by which to find the files
+    * @param  array   an array of file names that shall be excluded
+    */
+    function getSuitesFromDir($dir, $filenamePattern = '', $exclude = array())
+    {
+        if ($dir{strlen($dir)-1} == DIRECTORY_SEPARATOR) {
+            $dir = substr($dir, 0, -1);
+        }
+
+        $files = $this->_getFiles(realpath($dir), $filenamePattern, $exclude, realpath($dir . '/..'));
+        asort($files);
+
+        foreach ($files as $className => $aFile) {
+            include_once($aFile);
+
+            if (class_exists($className)) {
+                $suites[] =& new PHPUnit_TestSuite($className);
+            } else {
+                trigger_error("$className could not be found in $dir$aFile!");
+            }
+        }
+
+        $this->_gui->addSuites($suites);
+    }
+
+    /**
+    * This method searches recursively through the directories
+    * to find all the files that shall be added to the be visible.
+    *
+    * @param  string  the path where find the files
+    * @param  srting  the string pattern by which to find the files
+    * @param  string  the file names to be excluded
+    * @param  string  the root directory, which serves as the prefix to the fully qualified filename
+    * @access private
+    */
+    function _getFiles($dir, $filenamePattern, $exclude, $rootDir)
+    {
+        $files = array();
+
+        if ($dp = opendir($dir)) {
+            while (FALSE !== ($file = readdir($dp))) {
+                $filename = $dir . DIRECTORY_SEPARATOR . $file;
+                $match    = TRUE;
+
+                if ($filenamePattern && !preg_match("~$filenamePattern~", $file)) {
+                    $match = FALSE;
+                }
+
+                if (sizeof($exclude)) {
+                    foreach ($exclude as $aExclude) {
+                        if (strpos($file, $aExclude) !== FALSE) {
+                            $match = FALSE;
+                            break;
+                        }
+                    }
+                }
+
+                if (is_file($filename) && $match) {
+                    $tmp = str_replace($rootDir, '', $filename);
+
+                    if (strpos($tmp, DIRECTORY_SEPARATOR) === 0) {
+                        $tmp = substr($tmp, 1);
+                    }
+
+                    if (strpos($tmp, '/') === 0) {
+                        $tmp = substr($tmp, 1);
+                    }
+
+                    $className = str_replace(DIRECTORY_SEPARATOR, '_', $tmp);
+                    $className = basename($className, '.php');
+
+                    $files[$className] = $filename;
+                }
+
+                if ($file != '.' && $file != '..' && is_dir($filename)) {
+                    $files = array_merge($files, $this->_getFiles($filename, $filenamePattern, $exclude, $rootDir));
+                }
+            }
+
+            closedir($dp);
+        }
+
+        return $files;
+    }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/RepeatedTest.php
===================================================================
--- plog/trunk/class/test/PHPUnit/RepeatedTest.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/RepeatedTest.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,154 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: RepeatedTest.php,v 1.13 2005/11/10 09:47:14 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/TestDecorator.php';
+
+/**
+ * A Decorator that runs a test repeatedly.
+ *
+ * Here is an example:
+ *
+ * <code>
+ * <?php
+ * require_once 'PHPUnit.php';
+ * require_once 'PHPUnit/RepeatedTest.php';
+ *
+ * class MathTest extends PHPUnit_TestCase {
+ *     var $fValue1;
+ *     var $fValue2;
+ *
+ *     function MathTest($name) {
+ *         $this->PHPUnit_TestCase($name);
+ *     }
+ *
+ *     function setUp() {
+ *         $this->fValue1 = 2;
+ *         $this->fValue2 = 3;
+ *     }
+ *
+ *     function testAdd() {
+ *         $this->assertTrue($this->fValue1 + $this->fValue2 == 5);
+ *     }
+ * }
+ *
+ * $suite = new PHPUnit_TestSuite;
+ *
+ * $suite->addTest(
+ *   new PHPUnit_RepeatedTest(
+ *     new MathTest('testAdd'),
+ *     10
+ *   )
+ * );
+ *
+ * $result = PHPUnit::run($suite);
+ * print $result->toString();
+ * ?>
+ * </code>
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit_RepeatedTest extends PHPUnit_TestDecorator {
+    /**
+     * @var    integer
+     * @access private
+     */
+    var $_timesRepeat = 1;
+
+    /**
+     * Constructor.
+     *
+     * @param  object
+     * @param  integer
+     * @access public
+     */
+    function PHPUnit_RepeatedTest(&$test, $timesRepeat = 1) {
+        $this->PHPUnit_TestDecorator($test);
+        $this->_timesRepeat = $timesRepeat;
+    }
+
+    /**
+     * Counts the number of test cases that
+     * will be run by this test.
+     *
+     * @return integer
+     * @access public
+     */
+    function countTestCases() {
+        return $this->_timesRepeat * $this->_test->countTestCases();
+    }
+
+    /**
+     * Runs the decorated test and collects the
+     * result in a TestResult.
+     *
+     * @param  object
+     * @access public
+     * @abstract
+     */
+    function run(&$result) {
+        for ($i = 0; $i < $this->_timesRepeat; $i++) {
+            $this->_test->run($result);
+        }
+    }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/Skeleton.php
===================================================================
--- plog/trunk/class/test/PHPUnit/Skeleton.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/Skeleton.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,448 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Scott Mattocks <scott at crisscott.com>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: Skeleton.php,v 1.8 2005/11/10 09:47:14 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.1.0
+ */
+
+/**
+ * Class for creating a PHPUnit_TestCase skeleton file.
+ *
+ * This class will take a classname as a parameter on construction and will
+ * create a PHP file that contains the skeleton of a PHPUnit_TestCase
+ * subclass. The test case will contain a test foreach method of the class.
+ * Methods of the parent class will, by default, be excluded from the test
+ * class. Passing and optional construction parameter will include them.
+ *
+ * Example
+ *
+ *   <?php
+ *   require_once 'PHPUnit/Skeleton.php';
+ *   $ps = new PHPUnit_Skeleton('PHPUnit_Skeleton', 'PHPUnit/Skeleton.php');
+ *
+ *   // Generate the test class.
+ *   // Default settings will not include any parent class methods, but
+ *   // will include private methods.
+ *   $ps->createTestClass();
+ *
+ *   // Write the new test class to file.
+ *   // By default, code to run the test will be included.
+ *   $ps->writeTestClass();
+ *   ?>
+ *
+ * Now open the skeleton class and fill in the details.
+ * If you run the test as is, all tests will fail and
+ * you will see plenty of undefined constant errors.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Scott Mattocks <scott at crisscott.com>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.1.0
+ */
+class PHPUnit_Skeleton {
+    /**
+     * Path to the class file to create a skeleton for.
+     * @var string
+     */
+    var $classPath;
+
+    /**
+     * The name of the class
+     * @var string
+     */
+    var $className;
+
+    /**
+     * Path to the configuration file needed by class to test.
+     * @var string
+     */
+    var $configFile;
+
+    /**
+     * Whether or not to include the methods of the parent class when testing.
+     * @var boolean
+     */
+    var $includeParents;
+
+    /**
+     * Whether or not to test private methods.
+     * @var boolean
+     */
+    var $includePrivate;
+
+    /**
+     * The test class that will be created.
+     * @var string
+     */
+    var $testClass;
+
+    /**
+     * Constructor. Sets the class members and check that the class
+     * to test is accessible.
+     *
+     * @access public
+     * @param  string  $className
+     * @param  string  $classPath
+     * @param  boolean $includeParents Wheter to include the parent's methods in the test.
+     * @return void
+     */
+    function PHPUnit_Skeleton($className, $classPath, $includeParents = FALSE, $includePrivate = TRUE) {
+        // Set up the members.
+        if (@is_readable($classPath)) {
+            $this->className = $className;
+            $this->classPath = $classPath;
+        } else {
+            $this->_handleErrors($classPath . ' is not readable. Cannot create test class.');
+        }
+
+        // Do we want to include parent methods?
+        $this->includeParents = $includeParents;
+
+        // Do we want to allow private methods?
+        $this->includePrivate = $includePrivate;
+    }
+
+    /**
+     * The class to test may require a special config file before it can be
+     * instantiated. This method lets you set that file.
+     *
+     * @access public
+     * @param  string $configPath
+     * @return void
+     */
+    function setConfigFile($configFile) {
+        // Check that the file is readable
+        if (@is_readable($configFile)) {
+            $this->configFile = $configFile;
+        } else {
+            $this->_handleErrors($configFile . ' is not readable. Cannot create test class.');
+        }
+    }
+
+    /**
+     * Create the code that will be the skeleton of the test case.
+     *
+     * The test case must have a clss definition, one var, a constructor
+     * setUp, tearDown, and methods. Optionally and by default the code
+     * to run the test is added when the class is written to file.
+     *
+     * @access public
+     * @param  none
+     * @return void
+     */
+    function createTestClass() {
+        // Instantiate the object.
+        if (isset($this->configFile)) {
+            require_once $this->configFile;
+        }
+
+        require_once $this->classPath;
+
+        // Get the methods.
+        $classMethods = get_class_methods($this->className);
+
+        // Remove the parent methods if needed.
+        if (!$this->includeParents) {
+            $parentMethods = get_class_methods(get_parent_class($this->className));
+
+            if (count($parentMethods)) {
+                $classMethods = array_diff($classMethods, $parentMethods);
+            }
+        }
+
+        // Create the class definition, constructor, setUp and tearDown.
+        $this->_createDefinition();
+        $this->_createConstructor();
+        $this->_createSetUpTearDown();
+
+        if (count($classMethods)) {
+            // Foreach method create a test case.
+            foreach ($classMethods as $method) {
+                // Unless it is the constructor.
+                if (strcasecmp($this->className, $method) !== 0) {
+                  // Check for private methods.
+                  if (!$this->includePrivate && strpos($method, '_') === 0) {
+                      continue;
+                  } else {
+                      $this->_createMethod($method);
+                  }
+                }
+            }
+        }
+
+        // Finis off the class.
+        $this->_finishClass();
+    }
+
+    /**
+     * Create the class definition.
+     *
+     * The definition consist of a header comment, require statment
+     * for getting the PHPUnit file, the actual class definition,
+     * and the definition of the class member variable.
+     *
+     * All of the code needed for the new class is stored in the
+     * testClass member.
+     *
+     * @access private
+     * @param  none
+     * @return void
+     */
+    function _createDefinition() {
+        // Create header comment.
+        $this->testClass =
+          "/**\n" .
+          " * PHPUnit test case for " . $this->className . "\n" .
+          " * \n" .
+          " * The method skeletons below need to be filled in with \n" .
+          " * real data so that the tests will run correctly. Replace \n" .
+          " * all EXPECTED_VAL and PARAM strings with real data. \n" .
+          " * \n" .
+          " * Created with PHPUnit_Skeleton on " . date('Y-m-d') . "\n" .
+          " */\n";
+
+        // Add the require statements.
+        $this->testClass .= "require_once 'PHPUnit.php';\n";
+
+        // Add the class definition and variable definition.
+        $this->testClass .=
+          "class " . $this->className . "Test extends PHPUnit_TestCase {\n\n" .
+          "    var \$" . $this->className . ";\n\n";
+    }
+
+    /**
+     * Create the class constructor. (PHP4 style)
+     *
+     * The constructor simply calls the PHPUnit_TestCase method.
+     * This code is taken from the PHPUnit documentation.
+     *
+     * All of the code needed for the new class is stored in the
+     * testClass member.
+     *
+     * @access private
+     * @param  none
+     * @return void
+     */
+    function _createConstructor() {
+        // Create the test class constructor.
+        $this->testClass.=
+          "    function " . $this->className . "Test(\$name)\n" .
+          "    {\n" .
+          "        \$this->PHPUnit_TestCase(\$name);\n" .
+          "    }\n\n";
+    }
+
+    /**
+     * Create setUp and tearDown methods.
+     *
+     * The setUp method creates the instance of the object to test.
+     * The tearDown method releases the instance.
+     * This code is taken from the PHPUnit documentation.
+     *
+     * All of the code needed for the new class is stored in the
+     * testClass member.
+     *
+     * @access private
+     * @param  none
+     * @return void
+     */
+    function _createSetUpTearDown() {
+        // Create the setUp method.
+        $this->testClass .=
+          "    function setUp()\n" .
+          "    {\n";
+
+        if (isset($this->configFile)) {
+            $this->testClass .=
+            "        require_once '" . $this->configFile . "';\n";
+        }
+
+        $this->testClass .=
+          "        require_once '" . $this->classPath . "';\n" .
+          "        \$this->" . $this->className . " =& new " . $this->className . "(PARAM);\n" .
+          "    }\n\n";
+
+        // Create the tearDown method.
+        $this->testClass .=
+          "    function tearDown()\n" .
+          "    {\n" .
+          "        unset(\$this->" . $this->className . ");\n" .
+          "    }\n\n";
+    }
+
+    /**
+     * Create a basic skeleton for test methods.
+     *
+     * This code is taken from the PHPUnit documentation.
+     *
+     * All of the code needed for the new class is stored in the
+     * testClass member.
+     *
+     * @access private
+     * @param  none
+     * @return void
+     */
+    function _createMethod($methodName) {
+        // Create a test method.
+        $this->testClass .=
+          "    function test" . $methodName . "()\n" .
+          "    {\n" .
+          "        \$result   = \$this->" . $this->className . "->" . $methodName . "(PARAM);\n" .
+          "        \$expected = EXPECTED_VAL;\n" .
+          "        \$this->assertEquals(\$expected, \$result);\n" .
+          "    }\n\n";
+    }
+
+    /**
+     * Add the closing brace needed for a proper class definition.
+     *
+     * All of the code needed for the new class is stored in the
+     * testClass member.
+     *
+     * @access private
+     * @param  none
+     * @return void
+     */
+    function _finishClass() {
+        // Close off the class.
+        $this->testClass.= "}\n";
+    }
+
+    /**
+     * Create the code that will actually run the test.
+     *
+     * This code is added by default so that the test can be run
+     * just by running the file. To have it not added pass false
+     * as the second parameter to the writeTestClass method.
+     * This code is taken from the PHPUnit documentation.
+     *
+     * All of the code needed for the new class is stored in the
+     * testClass member.
+     *
+     * @access private
+     * @param  none
+     * @return void
+     */
+    function _createTest() {
+        // Create a call to the test.
+        $test =
+          "// Running the test.\n" .
+          "\$suite  = new PHPUnit_TestSuite('" . $this->className . "Test');\n" .
+          "\$result = PHPUnit::run(\$suite);\n" .
+          "echo \$result->toString();\n";
+
+        return $test;
+    }
+
+    /**
+     * Write the test class to file.
+     *
+     * This will write the test class created using the createTestClass
+     * method to a file called <className>Test.php. By default the file
+     * is written to the current directory and will have code to run
+     * the test appended to the bottom of the file.
+     *
+     * @access public
+     * @param  string  $destination The directory to write the file to.
+     * @param  boolean $addTest     Wheter to add the test running code.
+     * @return void
+     */
+    function writeTestClass($destination = './', $addTest = TRUE) {
+        // Check for something to write to file.
+        if (!isset($this->testClass)) {
+            $this->_handleErrors('Noting to write.', PHPUS_WARNING);
+            return;
+        }
+
+        // Open the destination file.
+        $fp = fopen($destination . $this->className . 'Test.php', 'w');
+        fwrite($fp, "<?php\n");
+
+        // Write the test class.
+        fwrite($fp, $this->testClass);
+
+        // Add the call to test the class in the file if we were asked to.
+        if ($addTest) {
+            fwrite($fp, $this->_createTest());
+        }
+
+        // Close the file.
+        fwrite($fp, "?>\n");
+        fclose($fp);
+    }
+
+    /**
+     * Error handler.
+     *
+     * This method should be rewritten to use the prefered error
+     * handling method. (PEAR_ErrorStack)
+     *
+     * @access private
+     * @param  string  $message The error message.
+     * @param  integer $type    An indication of the severity of the error.
+     * @return void             Code may cause PHP to exit.
+     */
+    function _handleErrors($message, $type = E_USER_ERROR) {
+        // For now just echo the message.
+        echo $message;
+
+        // Check to see if we should quit.
+        if ($type == E_USER_ERROR) {
+            exit;
+        }
+    }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/TestCase.php
===================================================================
--- plog/trunk/class/test/PHPUnit/TestCase.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/TestCase.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,293 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: TestCase.php,v 1.21 2005/11/10 09:47:14 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/Assert.php';
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/TestResult.php';
+
+/**
+ * A TestCase defines the fixture to run multiple tests.
+ *
+ * To define a TestCase
+ *
+ *   1) Implement a subclass of PHPUnit_TestCase.
+ *   2) Define instance variables that store the state of the fixture.
+ *   3) Initialize the fixture state by overriding setUp().
+ *   4) Clean-up after a test by overriding tearDown().
+ *
+ * Each test runs in its own fixture so there can be no side effects
+ * among test runs.
+ *
+ * Here is an example:
+ *
+ * <code>
+ * <?php
+ * class MathTest extends PHPUnit_TestCase {
+ *     var $fValue1;
+ *     var $fValue2;
+ *
+ *     function MathTest($name) {
+ *         $this->PHPUnit_TestCase($name);
+ *     }
+ *
+ *     function setUp() {
+ *         $this->fValue1 = 2;
+ *         $this->fValue2 = 3;
+ *     }
+ * }
+ * ?>
+ * </code>
+ *
+ * For each test implement a method which interacts with the fixture.
+ * Verify the expected results with assertions specified by calling
+ * assert with a boolean.
+ *
+ * <code>
+ * <?php
+ * function testPass() {
+ *     $this->assertTrue($this->fValue1 + $this->fValue2 == 5);
+ * }
+ * ?>
+ * </code>
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit_TestCase extends PHPUnit_Assert {
+    /**
+     * @var    boolean
+     * @access private
+     */
+    var $_failed = FALSE;
+
+    /**
+     * The name of the test case.
+     *
+     * @var    string
+     * @access private
+     */
+    var $_name = '';
+
+    /**
+     * PHPUnit_TestResult object
+     *
+     * @var    object
+     * @access private
+     */
+    var $_result;
+
+    /**
+     * Constructs a test case with the given name.
+     *
+     * @param  string
+     * @access public
+     */
+    function PHPUnit_TestCase($name = FALSE) {
+        if ($name !== FALSE) {
+            $this->setName($name);
+        }
+    }
+
+    /**
+     * Counts the number of test cases executed by run(TestResult result).
+     *
+     * @return integer
+     * @access public
+     */
+    function countTestCases() {
+        return 1;
+    }
+
+    /**
+     * Gets the name of a TestCase.
+     *
+     * @return string
+     * @access public
+     */
+    function getName() {
+        return $this->_name;
+    }
+
+    /**
+     * Runs the test case and collects the results in a given TestResult object.
+     *
+     * @param  object
+     * @return object
+     * @access public
+     */
+    function run(&$result) {
+        $this->_result = &$result;
+        $this->_result->run($this);
+
+        return $this->_result;
+    }
+
+    /**
+     * Runs the bare test sequence.
+     *
+     * @access public
+     */
+    function runBare() {
+        $this->setUp();
+        $this->runTest();
+        $this->tearDown();
+        $this->pass();
+    }
+
+    /**
+     * Override to run the test and assert its state.
+     *
+     * @access protected
+     */
+    function runTest() {
+        call_user_func(
+          array(
+            &$this,
+            $this->_name
+          )
+        );
+    }
+
+    /**
+     * Sets the name of a TestCase.
+     *
+     * @param  string
+     * @access public
+     */
+    function setName($name) {
+        $this->_name = $name;
+    }
+
+    /**
+     * Returns a string representation of the test case.
+     *
+     * @return string
+     * @access public
+     */
+    function toString() {
+        return '';
+    }
+
+    /**
+     * Creates a default TestResult object.
+     *
+     * @return object
+     * @access protected
+     */
+    function &createResult() {
+        return new PHPUnit_TestResult;
+    }
+
+    /**
+     * Fails a test with the given message.
+     *
+     * @param  string
+     * @access protected
+     */
+    function fail($message = '') {
+        if (function_exists('debug_backtrace')) {
+            $trace = debug_backtrace();
+
+            if (isset($trace['1']['file'])) {
+                $message = sprintf(
+                  "%s in %s:%s",
+
+                  $message,
+                  $trace['1']['file'],
+                  $trace['1']['line']
+                );
+            }
+        }
+
+        $this->_result->addFailure($this, $message);
+        $this->_failed = TRUE;
+    }
+
+    /**
+     * Passes a test.
+     *
+     * @access protected
+     */
+    function pass() {
+        if (!$this->_failed) {
+            $this->_result->addPassedTest($this);
+        }
+    }
+
+    /**
+     * Sets up the fixture, for example, open a network connection.
+     * This method is called before a test is executed.
+     *
+     * @access protected
+     * @abstract
+     */
+    function setUp() { /* abstract */ }
+
+    /**
+     * Tears down the fixture, for example, close a network connection.
+     * This method is called after a test is executed.
+     *
+     * @access protected
+     * @abstract
+     */
+    function tearDown() { /* abstract */ }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/TestDecorator.php
===================================================================
--- plog/trunk/class/test/PHPUnit/TestDecorator.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/TestDecorator.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,156 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: TestDecorator.php,v 1.17 2005/11/10 09:47:14 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/TestCase.php';
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/TestSuite.php';
+
+if (!function_exists('is_a')) {
+    require_once 'PHP/Compat/Function/is_a.php';
+}
+
+/**
+ * A Decorator for Tests.
+ *
+ * Use TestDecorator as the base class for defining new
+ * test decorators. Test decorator subclasses can be introduced
+ * to add behaviour before or after a test is run.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit_TestDecorator {
+    /**
+     * The Test to be decorated.
+     *
+     * @var    object
+     * @access protected
+     */
+    var $_test = NULL;
+
+    /**
+     * Constructor.
+     *
+     * @param  object
+     * @access public
+     */
+    function PHPUnit_TestDecorator(&$test) {
+        if (is_object($test) &&
+            (is_a($test, 'PHPUnit_TestCase') ||
+             is_a($test, 'PHPUnit_TestSuite'))) {
+
+            $this->_test = &$test;
+        }
+    }
+
+    /**
+     * Runs the test and collects the
+     * result in a TestResult.
+     *
+     * @param  object
+     * @access public
+     */
+    function basicRun(&$result) {
+        $this->_test->run($result);
+    }
+
+    /**
+     * Counts the number of test cases that
+     * will be run by this test.
+     *
+     * @return integer
+     * @access public
+     */
+    function countTestCases() {
+        return $this->_test->countTestCases();
+    }
+
+    /**
+     * Returns the test to be run.
+     *
+     * @return object
+     * @access public
+     */
+    function &getTest() {
+        return $this->_test;
+    }
+
+    /**
+     * Runs the decorated test and collects the
+     * result in a TestResult.
+     *
+     * @param  object
+     * @access public
+     * @abstract
+     */
+    function run(&$result) { /* abstract */ }
+
+    /**
+     * Returns a string representation of the test.
+     *
+     * @return string
+     * @access public
+     */
+    function toString() {
+        return $this->_test->toString();
+    }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/TestFailure.php
===================================================================
--- plog/trunk/class/test/PHPUnit/TestFailure.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/TestFailure.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,130 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: TestFailure.php,v 1.13 2005/11/10 09:47:14 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+/**
+ * A TestFailure collects a failed test together with the caught exception.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit_TestFailure {
+    /**
+     * @var    object
+     * @access private
+     */
+    var $_failedTest;
+
+    /**
+     * @var    string
+     * @access private
+     */
+    var $_thrownException;
+
+    /**
+     * Constructs a TestFailure with the given test and exception.
+     *
+     * @param  object
+     * @param  string
+     * @access public
+     */
+    function PHPUnit_TestFailure(&$failedTest, &$thrownException) {
+        $this->_failedTest      = &$failedTest;
+        $this->_thrownException = &$thrownException;
+    }
+
+    /**
+     * Gets the failed test.
+     *
+     * @return object
+     * @access public
+     */
+    function &failedTest() {
+        return $this->_failedTest;
+    }
+
+    /**
+     * Gets the thrown exception.
+     *
+     * @return object
+     * @access public
+     */
+    function &thrownException() {
+        return $this->_thrownException;
+    }
+
+    /**
+     * Returns a short description of the failure.
+     *
+     * @return string
+     * @access public
+     */
+    function toString() {
+        return sprintf(
+          "TestCase %s->%s() failed: %s\n",
+
+          get_class($this->_failedTest),
+          $this->_failedTest->getName(),
+          $this->_thrownException
+        );
+    }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/TestListener.php
===================================================================
--- plog/trunk/class/test/PHPUnit/TestListener.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/TestListener.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,162 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: TestListener.php,v 1.12 2005/11/10 09:47:15 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+/**
+ * A Listener for test progress.
+ *
+ * Here is an example:
+ *
+ * <code>
+ * <?php
+ * require_once 'PHPUnit.php';
+ * require_once 'PHPUnit/TestListener.php';
+ *
+ * class MathTest extends PHPUnit_TestCase {
+ *     var $fValue1;
+ *     var $fValue2;
+ *
+ *     function MathTest($name) {
+ *         $this->PHPUnit_TestCase($name);
+ *     }
+ *
+ *     function setUp() {
+ *         $this->fValue1 = 2;
+ *         $this->fValue2 = 3;
+ *     }
+ *
+ *     function testAdd() {
+ *         $this->assertTrue($this->fValue1 + $this->fValue2 == 4);
+ *     }
+ * }
+ *
+ * class MyListener extends PHPUnit_TestListener {
+ *     function addError(&$test, &$t) {
+ *         print "MyListener::addError() called.\n";
+ *     }
+ *
+ *     function addFailure(&$test, &$t) {
+ *         print "MyListener::addFailure() called.\n";
+ *     }
+ *
+ *     function endTest(&$test) {
+ *         print "MyListener::endTest() called.\n";
+ *     }
+ *
+ *     function startTest(&$test) {
+ *         print "MyListener::startTest() called.\n";
+ *     }
+ * }
+ *
+ * $suite = new PHPUnit_TestSuite;
+ * $suite->addTest(new MathTest('testAdd'));
+ *
+ * $result = new PHPUnit_TestResult;
+ * $result->addListener(new MyListener);
+ *
+ * $suite->run($result);
+ * print $result->toString();
+ * ?>
+ * </code>
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit_TestListener {
+    /**
+     * An error occurred.
+     *
+     * @param  object
+     * @param  object
+     * @access public
+     * @abstract
+     */
+    function addError(&$test, &$t) { /*abstract */ }
+
+    /**
+     * A failure occurred.
+     *
+     * @param  object
+     * @param  object
+     * @access public
+     * @abstract
+     */
+    function addFailure(&$test, &$t) { /*abstract */ }
+
+    /**
+     * A test ended.
+     *
+     * @param  object
+     * @access public
+     * @abstract
+     */
+    function endTest(&$test) { /*abstract */ }
+
+    /**
+     * A test started.
+     *
+     * @param  object
+     * @access public
+     * @abstract
+     */
+    function startTest(&$test) { /*abstract */ }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/TestResult.php
===================================================================
--- plog/trunk/class/test/PHPUnit/TestResult.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/TestResult.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,347 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: TestResult.php,v 1.18 2005/11/10 09:47:15 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/TestFailure.php';
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/TestListener.php';
+
+if (!function_exists('is_a')) {
+    require_once 'PHP/Compat/Function/is_a.php';
+}
+
+/**
+ * A TestResult collects the results of executing a test case.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit_TestResult {
+    /**
+     * @var    array
+     * @access protected
+     */
+    var $_errors = array();
+
+    /**
+     * @var    array
+     * @access protected
+     */
+    var $_failures = array();
+
+     /**
+     * @var    array
+     * @access protected
+     */
+    var $_listeners = array();
+
+    /**
+     * @var    array
+     * @access protected
+     */
+    var $_passedTests = array();
+
+    /**
+     * @var    integer
+     * @access protected
+     */
+    var $_runTests = 0;
+
+    /**
+     * @var    boolean
+     * @access private
+     */
+    var $_stop = FALSE;
+
+    /**
+     * Adds an error to the list of errors.
+     * The passed in exception caused the error.
+     *
+     * @param  object
+     * @param  object
+     * @access public
+     */
+    function addError(&$test, &$t) {
+        $this->_errors[] = new PHPUnit_TestFailure($test, $t);
+
+        for ($i = 0; $i < sizeof($this->_listeners); $i++) {
+            $this->_listeners[$i]->addError($test, $t);
+        }
+    }
+
+    /**
+     * Adds a failure to the list of failures.
+     * The passed in exception caused the failure.
+     *
+     * @param  object
+     * @param  object
+     * @access public
+     */
+    function addFailure(&$test, &$t) {
+        $this->_failures[] = new PHPUnit_TestFailure($test, $t);
+
+        for ($i = 0; $i < sizeof($this->_listeners); $i++) {
+            $this->_listeners[$i]->addFailure($test, $t);
+        }
+    }
+
+    /**
+     * Registers a TestListener.
+     *
+     * @param  object
+     * @access public
+     */
+    function addListener(&$listener) {
+        if (is_object($listener) &&
+            is_a($listener, 'PHPUnit_TestListener')) {
+            $this->_listeners[] = &$listener;
+        }
+    }
+
+    /**
+     * Adds a passed test to the list of passed tests.
+     *
+     * @param  object
+     * @access public
+     */
+    function addPassedTest(&$test) {
+        $this->_passedTests[] = &$test;
+    }
+
+    /**
+     * Informs the result that a test was completed.
+     *
+     * @param  object
+     * @access public
+     */
+    function endTest(&$test) {
+        for ($i = 0; $i < sizeof($this->_listeners); $i++) {
+            $this->_listeners[$i]->endTest($test);
+        }
+    }
+
+    /**
+     * Gets the number of detected errors.
+     *
+     * @return integer
+     * @access public
+     */
+    function errorCount() {
+        return sizeof($this->_errors);
+    }
+
+    /**
+     * Returns an Enumeration for the errors.
+     *
+     * @return array
+     * @access public
+     */
+    function &errors() {
+        return $this->_errors;
+    }
+
+    /**
+     * Gets the number of detected failures.
+     *
+     * @return integer
+     * @access public
+     */
+    function failureCount() {
+        return sizeof($this->_failures);
+    }
+
+    /**
+     * Returns an Enumeration for the failures.
+     *
+     * @return array
+     * @access public
+     */
+    function &failures() {
+        return $this->_failures;
+    }
+
+    /**
+     * Returns an Enumeration for the passed tests.
+     *
+     * @return array
+     * @access public
+     */
+    function &passedTests() {
+        return $this->_passedTests;
+    }
+
+    /**
+     * Unregisters a TestListener.
+     * This requires the Zend Engine 2 (to work properly).
+     *
+     * @param  object
+     * @access public
+     */
+    function removeListener(&$listener) {
+        for ($i = 0; $i < sizeof($this->_listeners); $i++) {
+            if ($this->_listeners[$i] === $listener) {
+                unset($this->_listeners[$i]);
+            }
+        }
+    }
+
+    /**
+     * Runs a TestCase.
+     *
+     * @param  object
+     * @access public
+     */
+    function run(&$test) {
+        $this->startTest($test);
+        $this->_runTests++;
+        $test->runBare();
+        $this->endTest($test);
+    }
+
+    /**
+     * Gets the number of run tests.
+     *
+     * @return integer
+     * @access public
+     */
+    function runCount() {
+        return $this->_runTests;
+    }
+
+    /**
+     * Checks whether the test run should stop.
+     *
+     * @access public
+     */
+    function shouldStop() {
+        return $this->_stop;
+    }
+
+    /**
+     * Informs the result that a test will be started.
+     *
+     * @param  object
+     * @access public
+     */
+    function startTest(&$test) {
+        for ($i = 0; $i < sizeof($this->_listeners); $i++) {
+            $this->_listeners[$i]->startTest($test);
+        }
+    }
+
+    /**
+     * Marks that the test run should stop.
+     *
+     * @access public
+     */
+    function stop() {
+        $this->_stop = TRUE;
+    }
+
+    /**
+     * Returns a HTML representation of the test result.
+     *
+     * @return string
+     * @access public
+     */
+    function toHTML() {
+        return '<pre>' . htmlspecialchars($this->toString()) . '</pre>';
+    }
+
+    /**
+     * Returns a text representation of the test result.
+     *
+     * @return string
+     * @access public
+     */
+    function toString() {
+        $result = '';
+
+        foreach ($this->_passedTests as $passedTest) {
+            $result .= sprintf(
+              "TestCase %s->%s() passed\n",
+
+              get_class($passedTest),
+              $passedTest->getName()
+            );
+        }
+
+        foreach ($this->_failures as $failedTest) {
+            $result .= $failedTest->toString();
+        }
+
+        return $result;
+    }
+
+    /**
+     * Returns whether the entire test was successful or not.
+     *
+     * @return boolean
+     * @access public
+     */
+    function wasSuccessful() {
+        if (empty($this->_errors) && empty($this->_failures)) {
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit/TestSuite.php
===================================================================
--- plog/trunk/class/test/PHPUnit/TestSuite.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit/TestSuite.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,262 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: TestSuite.php,v 1.17 2005/11/10 09:47:15 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/TestCase.php';
+
+/**
+ * A TestSuite is a Composite of Tests. It runs a collection of test cases.
+ *
+ * Here is an example using the dynamic test definition.
+ *
+ * <code>
+ * <?php
+ * $suite = new PHPUnit_TestSuite();
+ * $suite->addTest(new MathTest('testPass'));
+ * ?>
+ * </code>
+ *
+ * Alternatively, a TestSuite can extract the tests to be run automatically.
+ * To do so you pass the classname of your TestCase class to the TestSuite
+ * constructor.
+ *
+ * <code>
+ * <?php
+ * $suite = new TestSuite('classname');
+ * ?>
+ * </code>
+ *
+ * This constructor creates a suite with all the methods starting with
+ * "test" that take no arguments.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit_TestSuite {
+    /**
+     * The name of the test suite.
+     *
+     * @var    string
+     * @access private
+     */
+    var $_name = '';
+
+    /**
+     * The tests in the test suite.
+     *
+     * @var    array
+     * @access private
+     */
+    var $_tests = array();
+
+    /**
+     * Constructs a TestSuite.
+     *
+     * @param  mixed
+     * @access public
+     */
+    function PHPUnit_TestSuite($test = FALSE) {
+        if ($test !== FALSE) {
+            $this->setName($test);
+            $this->addTestSuite($test);
+        }
+    }
+
+    /**
+     * Adds a test to the suite.
+     *
+     * @param  object
+     * @access public
+     */
+    function addTest(&$test) {
+        $this->_tests[] = &$test;
+    }
+
+    /**
+     * Adds the tests from the given class to the suite.
+     *
+     * @param  string
+     * @access public
+     */
+    function addTestSuite($testClass) {		
+        if (class_exists($testClass)) {
+            $methods       = get_class_methods($testClass);
+            $parentClasses = array(strtolower($testClass));
+            $parentClass   = $testClass;
+
+            while(is_string($parentClass = get_parent_class($parentClass))) {
+                $parentClasses[] = $parentClass;
+            }
+
+            foreach ($methods as $method) {
+                if (substr($method, 0, 4) == 'test' &&
+                    !in_array($method, $parentClasses)) {
+                    $this->addTest(new $testClass($method));
+                }
+            }
+        }
+    }
+
+    /**
+     * Counts the number of test cases that will be run by this test.
+     *
+     * @return integer
+     * @access public
+     */
+    function countTestCases() {
+        $count = 0;
+
+        foreach ($this->_tests as $test) {
+            $count += $test->countTestCases();
+        }
+
+        return $count;
+    }
+
+    /**
+     * Returns the name of the suite.
+     *
+     * @return string
+     * @access public
+     */
+    function getName() {
+        return $this->_name;
+    }
+
+    /**
+     * Runs the tests and collects their result in a TestResult.
+     *
+     * @param  object
+     * @access public
+     */
+    function run(&$result) {
+        for ($i = 0; $i < sizeof($this->_tests) && !$result->shouldStop(); $i++) {
+            $this->_tests[$i]->run($result);
+        }
+    }
+
+    /**
+     * Runs a test.
+     *
+     * @param  object
+     * @param  object
+     * @access public
+     */
+    function runTest(&$test, &$result) {
+        $test->run($result);
+    }
+
+    /**
+     * Sets the name of the suite.
+     *
+     * @param  string
+     * @access public
+     */
+    function setName($name) {
+        $this->_name = $name;
+    }
+
+    /**
+     * Returns the test at the given index.
+     *
+     * @param  integer
+     * @return object
+     * @access public
+     */
+    function &testAt($index) {
+        if (isset($this->_tests[$index])) {
+            return $this->_tests[$index];
+        } else {
+            return FALSE;
+        }
+    }
+
+    /**
+     * Returns the number of tests in this suite.
+     *
+     * @return integer
+     * @access public
+     */
+    function testCount() {
+        return sizeof($this->_tests);
+    }
+
+    /**
+     * Returns the tests as an enumeration.
+     *
+     * @return array
+     * @access public
+     */
+    function &tests() {
+        return $this->_tests;
+    }
+
+    /**
+     * Returns a string representation of the test suite.
+     *
+     * @return string
+     * @access public
+     */
+    function toString() {
+        return '';
+    }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/PHPUnit.php
===================================================================
--- plog/trunk/class/test/PHPUnit.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/PHPUnit.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,134 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * PHP Version 4
+ *
+ * Copyright (c) 2002-2005, Sebastian Bergmann <sb at sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    CVS: $Id: PHPUnit.php,v 1.17 2005/11/10 09:47:11 sebastian Exp $
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      File available since Release 1.0.0
+ */
+
+define( "PHPUNIT_CLASS_PATH", PLOG_CLASS_PATH."class/test/" );
+
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/TestCase.php';
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/TestResult.php';
+require_once PHPUNIT_CLASS_PATH.'PHPUnit/TestSuite.php';
+
+/**
+ * PHPUnit runs a TestSuite and returns a TestResult object.
+ *
+ * Here is an example:
+ *
+ * <code>
+ * <?php
+ * require_once 'PHPUnit.php';
+ *
+ * class MathTest extends PHPUnit_TestCase {
+ *     var $fValue1;
+ *     var $fValue2;
+ *
+ *     function MathTest($name) {
+ *       $this->PHPUnit_TestCase($name);
+ *     }
+ *
+ *     function setUp() {
+ *       $this->fValue1 = 2;
+ *       $this->fValue2 = 3;
+ *     }
+ *
+ *     function testAdd() {
+ *       $this->assertTrue($this->fValue1 + $this->fValue2 == 5);
+ *     }
+ * }
+ *
+ * $suite = new PHPUnit_TestSuite();
+ * $suite->addTest(new MathTest('testAdd'));
+ *
+ * $result = PHPUnit::run($suite);
+ * print $result->toHTML();
+ * ?>
+ * </code>
+ *
+ * Alternatively, you can pass a class name to the PHPUnit_TestSuite()
+ * constructor and let it automatically add all methods of that class
+ * that start with 'test' to the suite:
+ *
+ * <code>
+ * <?php
+ * $suite  = new PHPUnit_TestSuite('MathTest');
+ * $result = PHPUnit::run($suite);
+ * print $result->toHTML();
+ * ?>
+ * </code>
+ *
+ * @category   Testing
+ * @package    PHPUnit
+ * @author     Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @copyright  2002-2005 Sebastian Bergmann <sb at sebastian-bergmann.de>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PHPUnit
+ * @since      Class available since Release 1.0.0
+ */
+class PHPUnit {
+    /**
+     * Runs a test(suite).
+     *
+     * @param  mixed
+     * @return PHPUnit_TestResult
+     * @access public
+     */
+    function &run(&$suite) {
+        $result = new PHPUnit_TestResult();
+        $suite->run($result);
+
+        return $result;
+    }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+?>

Added: plog/trunk/class/test/testrunner.class.php
===================================================================
--- plog/trunk/class/test/testrunner.class.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/testrunner.class.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,105 @@
+<?php
+
+	/**
+	 * \addgroup Test
+	 *
+	 * This class takes care of running all unit tests in LifeType, as many as there are. This class
+	 * process the contents of the class/test/tests/ folder and loads all the classes whose name
+	 * ends with "_test.class.php" and uses PHPUnit to process them.
+	 *
+	 * The correct way to use this class is as follows:
+	 *
+	 * <pre>	
+	 *  $r = new TestRunner();
+	 *  $result = $r->run();
+     *  print( $result->toHTML());
+     * </pre>
+     *
+	 * In order to add new test cases, please reproduce the class/ structure in the class/test/tests folder
+	 * (so that it is easier to tell which class each one of the tests is taking care of) and call your class
+	 * ClassThatIsBeingTested_test.class.php. The TestRunner class will load them automatically and execute any
+	 * methods whose name starts with "test". Please the PHPUnit documentation for more details on how to
+	 * implement test cases.
+	 */
+	
+	include_once( PLOG_CLASS_PATH."class/misc/glob.class.php" );
+	include_once( PLOG_CLASS_PATH."class/file/file.class.php" );	
+	include_once( PLOG_CLASS_PATH."class/test/PHPUnit.php" );
+	
+	/**
+	 * base folder where all test cases are located
+	 */
+	define( "TEST_CLASS_FOLDER", PLOG_CLASS_PATH."class/test/tests" );
+	
+	/**
+	 * pattern for test class names
+	 */
+	define( "TEST_CLASS_NAME_PATTERN", "*_test.class.php" );
+	
+	class TestRunner
+	{
+		var $folder;
+		var $pattern;
+		var $files;
+		var $suite;
+		
+		function TestRunner( $folder = TEST_CLASS_FOLDER, $pattern = TEST_CLASS_NAME_PATTERN )
+		{
+			$this->folder = $folder;
+			$this->pattern = $pattern;
+			
+			$this->files = $this->_findClasses( $this->folder, $this->pattern );
+		}
+		
+		function run()
+		{
+			// process all the classes and add them to the test suite
+			$this->suite = new PHPUnit_TestSuite();
+			foreach( $this->files as $file ) {
+				// load the class file
+				include_once( $file );
+				// and create an instance of it
+				$className = str_replace( ".class.php", "", basename( $file ));
+				$this->suite->addTestSuite( $className );
+			}			
+			
+			// after adding all the tests, run the suite and return the result
+			$result = PHPUnit::run( $this->suite );
+			
+			return( $result );
+		}
+		
+		/**
+		 * @private
+		 *
+		 * Returns a list of all the files in the given folder that match the given pattern. In this case
+		 * it is used to easily find all the test classes. Later on these classes will be loaded, instantiated
+		 * and a test suite will be automatically created.
+		 */
+		function _findClasses( $folder = null, $pattern = "*" )
+		{
+			$list = Array();
+			
+			$files = Glob::myGlob( $folder , "*" );
+			foreach( $files as $file ) {
+				// recursive call
+				if( File::isDir( $file )) {
+					$res = $this->_findClasses( $file, $pattern );
+					foreach( $res as $f ) {
+						$list[] = $f;
+					}
+				}
+				else {
+					if ( File::isReadable( $file )) {
+						if( Glob::fnmatch( $pattern, $file )) {
+							// add the file only if it matched our pattern
+							$list[] = $file;
+						}
+					}
+				}					
+			}
+			
+			return( $list );
+		}
+	}
+?>
\ No newline at end of file

Added: plog/trunk/class/test/tests/data/validator/integervalidator_test.class.php
===================================================================
--- plog/trunk/class/test/tests/data/validator/integervalidator_test.class.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/tests/data/validator/integervalidator_test.class.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,55 @@
+<?php
+
+	include_once( PLOG_CLASS_PATH."class/test/PHPUnit.php" );
+	include_once( PLOG_CLASS_PATH."class/data/validator/integervalidator.class.php" );
+
+	/**
+	 * \ingroup Tests
+	 *
+	 * Test case for the IntegerValidator class
+	 */
+	class IntegerValidator_Test extends PHPUnit_TestCase
+	{
+		function setUp()
+		{
+			// a signed and an unsigned validator
+			$this->v = new IntegerValidator();
+			$this->signed = new IntegerValidator( true );
+		}
+		
+		function testUnsigned()
+		{
+			$this->assertTrue( $this->v->validate( "145" ));
+		}
+
+		function testSignedPositive()
+		{
+			$this->assertTrue( $this->signed->validate( "+332" ));
+		}
+
+		function testSignedNegative()
+		{
+			$this->assertTrue( $this->signed->validate( "-21" ));
+		}
+		
+		function testSignedNoSign()
+		{
+			$this->assertTrue( $this->signed->validate( "21" ));			
+		}
+		
+		function testSignedNotInteger()
+		{
+			$this->assertFalse( $this->v->validate( "+221adsf" ));			
+		}
+		
+		function testNotInteger()
+		{
+			$this->assertFalse( $this->v->validate( "443.23" ));
+		}
+		
+		function testString()
+		{
+			$this->assertFalse( $this->v->validate( "not_an_integer" ));
+		}		
+	}
+?>
\ No newline at end of file

Added: plog/trunk/class/test/tests/net/url_test.class.php
===================================================================
--- plog/trunk/class/test/tests/net/url_test.class.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/class/test/tests/net/url_test.class.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,73 @@
+<?php
+
+	include_once( PLOG_CLASS_PATH."class/test/PHPUnit.php" );
+	include_once( PLOG_CLASS_PATH."class/net/url.class.php" );
+
+	/**
+	 * \ingroup Tests
+	 *
+	 * Test case for the Url class
+	 */
+	class Url_Test extends PHPUnit_TestCase
+	{
+		var $url;
+			
+		function setUp()
+		{
+			$this->url = new Url( "http://user:password@www.test-server.com:8080/path/to/script/test.php?param1=value1&param2=value2#fragment" );
+		}
+		
+		function testGetHost()
+		{
+			$this->assertEquals( $this->url->getHost(), "www.test-server.com" );
+		}
+		
+		function testGetUser()
+		{
+			$this->assertEquals( $this->url->getUser(), "user" );
+		}
+		
+		function testGetPass()
+		{
+			$this->assertEquals( $this->url->getPass(), "password" );
+		}
+		
+		function testGetPort()
+		{
+			$this->assertEquals( $this->url->getPort(), "8080" );
+		}
+		
+		function testGetPath()
+		{
+			$this->assertEquals( $this->url->getPath(), "/path/to/script/test.php" );
+		}
+		
+		function testGetQuery()
+		{
+			$this->assertEquals( $this->url->getQuery(), "param1=value1&param2=value2" );
+		}
+		
+		function testGetFragment()
+		{
+			$this->assertEquals( $this->url->getFragment(), "fragment" );			
+		}
+		
+		function testSetHost()
+		{
+			$this->url->setHost( "www.lifetype.net" );
+			$this->assertEquals( $this->url->getHost(), "www.lifetype.net" );
+		}
+		
+		function testSetQuery()
+		{
+			$this->url->setQuery( "a=b&c=d" );
+			$this->assertEquals( $this->url->getQuery(), "a=b&c=d" );			
+		}
+		
+		function testSetPath()
+		{
+			$this->url->setPath( "/blog.php/development_blog" );
+			$this->assertEquals( $this->url->getPath(), "/blog.php/development_blog" );
+		}
+	}
+?>
\ No newline at end of file

Added: plog/trunk/runtests.php
===================================================================
--- plog/trunk/runtests.php	2006-07-05 12:22:56 UTC (rev 3688)
+++ plog/trunk/runtests.php	2006-07-05 14:32:15 UTC (rev 3689)
@@ -0,0 +1,16 @@
+<?php
+
+	if (!defined( "PLOG_CLASS_PATH" )) {
+	    define( "PLOG_CLASS_PATH", dirname(__FILE__)."/");
+	}
+
+	include_once( PLOG_CLASS_PATH."class/test/testrunner.class.php" );
+
+	// create a new TestRunner class, which will take care of loading all our
+	// tests cases, instantiate them and tell PHPUnit to run the tests
+	$r = new TestRunner();
+	$result = $r->run();
+	
+	// check the results when ready
+	print( $result->toHTML());
+?>
\ No newline at end of file



More information about the pLog-svn mailing list