Test::C2FIT::ColumnFixture - A ColumnFixture maps columns in the test data to fields or methods of its subclasses.


Test-C2FIT documentation Contained in the Test-C2FIT distribution.

Index


Code Index:

NAME

Top

Test::C2FIT::ColumnFixture - A ColumnFixture maps columns in the test data to fields or methods of its subclasses.

SYNOPSIS

Top

Normally, you subclass ColumnFixture.

	package MyColumnFixture;
	use base 'Test::C2FIT::ColumnFixture;'

	sub getX {
	 my $self = shift;
	 return $self->{X};
	}

DESCRIPTION

Top

Column headings with braces (e.g. getX()) will get bound to methods, i.e. the data entered in your document will be checked against the result of the respective method. A Column heading consisting of more words will be concatened to a camel-case name ("get name ()" will be mapped to "getName()")

Column headings without braces will be bound to instance variables (=fields). In perl these need not to be predeclared. E.g. when column heading is "surname", then the ColumnFixture puts the text of the respective cell to a variable which can be used by $self->{surname}. A Column heading consisting of more words will be concatened to a camel-case name ("given name" will be mapped to "givenName")

When your data is not stored as string, then you'll propably need an TypeAdapter. See more in Fixture.

METHODS

Top

reset()

Will be called before a row gets processed

execute()

Will be called either after a row has been processed or before the first usage of a method-column in the row, depending upon which case occurs first.

SEE ALSO

Top

Extensive and up-to-date documentation on FIT can be found at: http://fit.c2.com/


Test-C2FIT documentation Contained in the Test-C2FIT distribution.

# $Id: ColumnFixture.pm,v 1.8 2006/06/16 15:20:56 tonyb Exp $
#
# Copyright (c) 2002-2005 Cunningham & Cunningham, Inc.
# Released under the terms of the GNU General Public License version 2 or later.
#
# Perl translation by Dave W. Smith <dws@postcognitive.com>
# Modified by Tony Byrne <fit4perl@byrnehq.com>

package Test::C2FIT::ColumnFixture;

use base 'Test::C2FIT::Fixture';
use strict;
use Test::C2FIT::TypeAdapter;
use Error qw( :try );

sub new {
    my $pkg = shift;
    return $pkg->SUPER::new( columnBindings => [], hasExecuted => 0, @_ );
}

sub doRows {
    my $self = shift;
    my ($rows) = @_;
    $self->bind( $rows->parts() );
    $self->SUPER::doRows( $rows->more() );
}

sub doRow {
    my $self = shift;
    my ($row) = @_;

    $self->{'hasExecuted'} = 0;
    try {
        $self->reset();
        $self->SUPER::doRow($row);
        $self->execute unless $self->{'hasExecuted'};
      }
      otherwise {
        my $e = shift;
        $self->exception( $row->leaf(), $e );
      };
}

sub doCell {
    my $self = shift;
    my ( $cell, $column ) = @_;

    my $adapter = $self->{'columnBindings'}->[$column];
    eval {
        my $string = $cell->text();
        if ( $string eq "" ) {
            $self->check( $cell, $adapter );
        }
        elsif ( not defined($adapter) ) {
            $self->ignore($cell);
        }
        elsif ( $adapter->field() ) {
            $adapter->set( $adapter->parse($string) );
        }
        elsif ( $adapter->method() ) {
            $self->check( $cell, $adapter );
        }
    };
    if ($@) {
        $self->exception( $cell, $@ );
    }
}

sub check {
    my $self = shift;
    my ( $cell, $adapter ) = @_;

    if ( $self->{'hasExecuted'} ) {
        $self->SUPER::check( $cell, $adapter );
    }
    elsif ( !$self->{'hasExecuted'} ) {
        $self->{'hasExecuted'} = 1;
        try {
            $self->execute();
            $self->SUPER::check( $cell, $adapter );
          }
          otherwise {
            my $e = shift;
            $self->exception( $cell, $e );
          };
    }
}

sub reset {
    my ($self) = @_;

    # about to process first cell of row
}

sub execute {
    my ($self) = @_;

    # about to process first method call of row
}

sub bind {
    my ( $self, $heads ) = @_;
    my $column = 0;

    $self->{'columnBindings'} = [];
    while ($heads) {
        my $name = $heads->text();
        try {
            if ( $name eq "" ) {
                $self->{'columnBindings'}->[$column] = undef;
            }
            elsif ( $name =~ /^(.*)\(\)$/ ) {
                $self->{'columnBindings'}->[$column] =
                  $self->bindMethod( $self->camel($1) );
            }
            else {
                $self->{'columnBindings'}->[$column] =
                  $self->bindField( $self->camel($name) );
            }
          }
          otherwise {
            my $e = shift;
            $self->exception( $heads, $e );
          };
        $heads = $heads->more();
        ++$column;
    }
}

sub bindMethod {
    my $self = shift;
    my ($name) = @_;
    return Test::C2FIT::TypeAdapter->onMethod( $self, $name );
}

sub bindField {
    my $self = shift;
    my ($name) = @_;
    return Test::C2FIT::TypeAdapter->onField( $self, $name );
}

sub getTargetClass {
    my $self = shift;
    ref($self);
}

1;

__END__

package fit;

// Copyright (c) 2002 Cunningham & Cunningham, Inc.
// Released under the terms of the GNU General Public License version 2 or later.

public class ColumnFixture extends Fixture {

    protected TypeAdapter columnBindings[];
    protected boolean hasExecuted = false;

    // Traversal ////////////////////////////////

    public void doRows(Parse rows) {
        bind(rows.parts);
        super.doRows(rows.more);
    }

    public void doRow(Parse row) {
        hasExecuted = false;
        try {
            reset();
            super.doRow(row);
            if (!hasExecuted) {
                execute();
            }
        } catch (Exception e) {
            exception (row.leaf(), e);
        }
    }

    public void doCell(Parse cell, int column) {
        TypeAdapter a = columnBindings[column];
        try {
            String text = cell.text();
            if (text.equals("")) {
                check(cell, a);
            } else if (a == null) {
                ignore(cell);
            } else if (a.field != null) {
                a.set(a.parse(text));
            } else if (a.method != null) {
                check(cell, a);
            }
        } catch(Exception e) {
            exception(cell, e);
        }
    }

    public void check(Parse cell, TypeAdapter a) {
        if (!hasExecuted) {
            try {
                execute();
            } catch (Exception e) {
                exception (cell, e);
            }
            hasExecuted = true;
        }
        super.check(cell, a);
    }

    public void reset() throws Exception {
        // about to process first cell of row
    }

    public void execute() throws Exception {
        // about to process first method call of row
    }

    // Utility //////////////////////////////////

    protected void bind (Parse heads) {
        columnBindings = new TypeAdapter[heads.size()];
        for (int i=0; heads!=null; i++, heads=heads.more) {
            String name = heads.text();
            String suffix = "()";
            try {
                if (name.equals("")) {
                    columnBindings[i] = null;
                } else if (name.endsWith(suffix)) {
                    columnBindings[i] = bindMethod(name.substring(0,name.length()-suffix.length()));
                } else {
                    columnBindings[i] = bindField(name);
                }
            }
            catch (Exception e) {
                exception (heads, e);
            }
        }

    }

    protected TypeAdapter bindMethod (String name) throws Exception {
        return TypeAdapter.on(this, getTargetClass().getMethod(camel(name), new Class[]{}));
    }

    protected TypeAdapter bindField (String name) throws Exception {
        return TypeAdapter.on(this, getTargetClass().getField(camel(name)));
    }

    protected Class getTargetClass() {
        return getClass();
    }
}