PHPAutoTest - Automatically runs your tests as you work

Ye' old general discussion board. Basically, for everything that isn't covered elsewhere. Come here to shoot the breeze, shoot your mouth off, or whatever suits your fancy.
This forum is not for asking programming related questions.

Moderator: General Moderators

Post Reply
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

PHPAutoTest - Automatically runs your tests as you work

Post by josh »

Code: Select all

 
<?php
/**
* Based loosely upon the designs of autotest.rb and ruby auto test utility(s)
* 
* Pass the path you want to recurisvely monitor as the only command line argument
* Override or change doDelay() and runTests() to suite your environment
* 
*
* - override runTests() with the command you want to run
* 
* - override doDelay() to check more/less often
* 
* - pass the path to files in the contstructor
* 
* - pass a log level to the constructor if you would like helpful output
*   (although this may interfere with ability to read your test failures if your delay is a low # )
*
* Invoke like this:
* C:/wamp/bin/php/php5.3.0/php E:\dev\path\phpautotest.php E:\dev\path\to\monitor
* 
* 
* @license code is licensed persuant to Open Software License ("OSL") v. 3.0
* 
* You may use it within your applications without providing credit
* Any modifications or derivative works must be licensed OSL v 3.0 unless express written consent provided
* 
* @author Josh Ribakoff <josh.ribakoff@gmail.com> http://www.ne8.net
*/
if( isset( $argv[1] ) )
{
    $path = trim( $argv[1] );
}
if( !$path )
{
    exit();
}
$test = new PHPAutoTest( $path );
$test->main();
 
/**
* The main test controller
*/
class PHPAutoTest
{
    protected $path;
    
    /**
    * No log messages
    */
    const NONE = 0;
    
    /**
    * Notify when file checking starts/stops
    */
    const CHANGE_LOOP = 1;
    
    /**
    * Notify when changes are detected
    */
    const CHANGED_FILES = 2;
    
    /**
    * @var array of PHPAutoTest_File
    */
    protected $files = array();
    
    /**
    * @var PHPAutoTest_Logger
    */
    protected $logger;
    
    /**
    * @param mixed $path path of files to monitor
    * @param mixed $logLevel set to NONE, CHANGE_LOOP, or CHANGED_FILES
    */
    public function __construct( $path, $logLevel = 2)
    {
        $this->path = $path;
        
        $this->logger = new PHPAutoTest_Logger( $logLevel );
    }
    
    public function main()
    {
        while( true )
        {
            $this->logger->log( "checking files, please wait", self::CHANGE_LOOP );
            $run = false;
            foreach( $this->filesMonitoring() as $file )
            {
                if( $file->hasDeleted() )
                {
                    $run = true;    
                }
                if( $file->hasModified( ) )
                {
                    $run = true;
                }
            }
            if( $run )
            {
                $this->logger->log( "changes detected", self::CHANGE_LOOP );
                $this->runTests();
            }
            $this->logger->log( "done", self::CHANGE_LOOP );
            $this->doDelay();
        }
    }
    
    protected function doDelay()
    {
        sleep( 4 );   
    }
    
    protected function runTests()
    {
        passthru( 'tests.bat' );
    }
    
    /**
    * @return array of PHPAutoTest_File
    */
    function filesMonitoring()
    {
        $files = $this->recursiveGlob( $this->path );
        $return = array();
        foreach( $files as $file )
        {
            if( isset( $this->files[ md5( $file ) ] ) )
            {
                $fileObj = $this->files[ md5( $file ) ];
                array_push( $return, $fileObj );
                if( $fileObj->hasDeleted() )
                {
                    unset( $this->files[ $fileObj->getHash() ] );
                }
                continue;
            }
            $file = new PHPAutoTest_File( $file, $this->logger );
            array_push( $return, $file );
            $this->files[ $file->getHash() ] = $file;
        }
        return $return;
    }
    
    protected function recursiveGlob( $path )
    {
        $files = Array();
        $file_tmp= glob( $path . '*',GLOB_MARK | GLOB_NOSORT);
        foreach($file_tmp as $item)
        {
            if(substr($item,-1)!=DIRECTORY_SEPARATOR)
            {
                $files[] = $item;
            }
            else
            {
                $files = array_merge($files, $this->recursiveGlob($item));
            }
        }
        return $files;
    }
}
 
/**
* Each file is a PHPAutoTest_File object
*/
class PHPAutoTest_File
{
    protected $file;
    
    protected $modified;
    
    protected $logger;
    
    public function __construct( $file, PHPAutoTest_Logger $logger )
    {
        $this->file = $file;
        $this->logger = $logger;
    }
    
    public function isFile()
    {
        return filetype( $this->file ) == 'file';
    }
    
    public function hasDeleted()
    {
        if( !file_exists( $this->file ) )
        {
            return true;
        }
    }
    
    /**
    * put your comment there...
    * 
    * @return boolean true if need to re-run tests, otherwise false
    */
    public function hasModified()
    {
        if( !$this->isFile() )
        {
            return false;
        }
        $modified = filemtime( $this->file );
        $return = (bool)( $modified > $this->modified && $this->modified != 0 );
        if( $return ) $this->logger->log( $this->file . " modified at " . $modified, PHPAutoTest::CHANGED_FILES );
        $this->modified = $modified;
        return $return;
               
    }
    
    public function getHash()
    {
        return md5( $this->file );
    }
}
 
class PHPAutoTest_Logger
{
    protected $logLevel;
    
    public function __construct( $logLevel )
    {
        $this->logLevel = $logLevel;
    }
    
    public function log( $msg, $level )
    {
        if( $this->logLevel >= $level )
        {
            echo $msg . "\n";
        }    
    }
}
 
November 19: updated, fixed a bug w/ logger and sprouted logger class
November 19: updated again
Post Reply