<?php
/**
 * FIT Fixture: Row
 * 
 * $Id$
 * 
 * @author gERD Schaufelberger <gerd@php-tools.net>
 * @package FIT
 * @subpackage Fixture
 * @license LGPL http://www.gnu.org/copyleft/lesser.html
 */

/**
 * FIT Fixture: Row
 * 
 * A RowFixture compares rows in the test data to objects in the 
 * system under test. Methods are invoked on the objects and 
 * returned values compared to those in the table. An algorithm 
 * matches rows with objects based on one or more keys. Objects 
 * may be missing or in surplus and are so noted.
 * 
 * The fixture processes all the rows of one table following these five steps:
 *
 * - bind the columns to variables and methods by reflection.
 * - query to get the result rows which will be checked.
 * - match the expected and result rows and check the matches.
 * - build html for missing rows.
 * - mark mark missing and surplus rows as such.
 *
 * @version 0.1.0
 * @package FIT
 * @subpackage Fixture
 */
class Testing_FIT_Fixture_Row extends Testing_FIT_Fixture 
{
    protected   
$_results   =   array();

   
/**
    * bind columsn to fixture and start row iterator
    * 
    * @param object $node
    * @return boolean true on success
    */
    
public function doRowsTesting_FIT_Node $node 
    {
        
$node->next();
        
$this->_bind$node );
        
        
$this->_results =   $this->query();
        
        
parent::doRows$node );
        
        
// add surplus data to output table
        
$parser =   $node->getParser();
        foreach( 
$this->_results as $plus ) {
            
$parser->appendRow$node->table );
            
            
$cells  =   $node->getRowIterator();
            while( 
$cells->valid() ) {
                
$cells->cData   =   $plus[$this->_columnBindings[$cells->key()]['name']];
                
$cells->attributes =   array();
                
$cells->next();
            }
            
$node->markWrong'surplus' );
            
$node->next();
        }
        
        return 
true;
    }
    
   
/**
    * match cells
    * 
    * Mark matching rows as right  and missing ones as wrong.
    * In case there are some lines left, they are marked as surplus
    * 
    * @param object $node
    * @return boolean true on success
    */
    
public function doCellsTesting_FIT_Node $node )
    {
        
$this->_current =   array();        
        
parent::doCells$node );
        
        
$match  =   true;
        for( 
$i 0$i count$this->_results ); ++$i ) {        
            
$match  =   true;
            
            foreach( 
$this->_current as $key => $cData ) {
                if( 
$this->_results[$i][$key] != $cData ) {
                    
$match  =   false;
                    break;
                }
            }
            
            if( 
$match ) {
                
// this line matches
                
$node->markRight();
                unset( 
$this->_results[$i] );
                
$this->_results =   array_values$this->_results );
                return 
true;
            }
        }
        
        
// this line is missing
        
$node->markWrong'missing' );
        return 
true;
    }
    
   
/**
    * match rows
    * 
    * @param object $node
    * @return boolean true on success
    */
    
public function doCellTesting_FIT_Node $node )
    {
        
$no     =   $node->key();
        
$bind   =   $this->_columnBindings[$no];
        
        
$this->_current[$bind['name']]  =   $this->_columnFilter[$no]->in$node->cData );
        return 
true;
    }
    
   
/**
    * match rows
    * 
    * @param object $node
    * @return boolean true on success
    */
    
protected function _matchTesting_FIT_Node $node )
    {
        while( 
$node->valid() ) {
        
            
$cells  $node->getRowIterator();
            
            foreach( 
$cells as $no => $cdata ) {
            
                if( 
$bind['type'] == 'property' ) {
                    
$this->$bind['name']    =   $this->_columnFilter[$no]->in$cdata );
                    continue;
                }
                
$cells->markIgnore();
            }
            
$node->next();
        }
        
        return 
true;
    }    

}
?>