package PROP::ObjectTest;

use strict;
use base qw/Test::Unit::TestCase/;
use PROP::DBH;
use PROP::TestCommon;
use PROP::Util;
use PROP::Link;

sub new {
    my ($invocant, @args) = @_;
    my $self = $invocant->SUPER::new(@args);

    return $self;
}

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

    drop_tables();
    create_tables();
}

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

    drop_tables();
}

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

    my $class = 'Dummy::Foo';

    # first see if the guard clauses for add_field_verifier work...

    eval {
	PROP::Object::add_field_verifier({});
    };
    my $err = $@;
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($err));
    $self->assert_matches(qr/invalid invocant/, $err);

    eval {
	$class->add_field_verifier('blah');
    };
    $err = $@;
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($err));
    $self->assert_matches(qr/unknown field 'blah' specified/, $err);

    eval {
	$class->add_field_verifier('bar', "not a code ref!");
    };
    $err = $@;
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($err));
    $self->assert_matches(qr/verifier must be a code ref/, $err);

    # create a couple of objects to play with
    my @objects = ($class->new(), $class->new());

    # this should work, because we have no field verifiers
    eval {
	$objects[0]->set_field_value('bar', 'blah');
	$objects[1]->set_field_value('bar', 'meh');
    };
    $self->assert_equals('', $@);

    # this should work because we're not abusing the method arguments
    eval {
	$class->add_field_verifier('bar', sub { shift() =~ /\d+/; });
    };
    $self->assert_str_equals('', $@);

    eval {
	$objects[0]->add_field_verifier('bar', sub { $_[0] > 3 });
    };
    $self->assert_str_equals('', $@);

    # this should work because we obey the wishes of the field verifiers
    eval {
	$objects[0]->set_field_value('bar', 5);
	$objects[1]->set_field_value('bar', 1);
    };
    $self->assert_str_equals('', $@);

    # this should work because we set a field that isn't verified
    eval {
	$objects[0]->set_field_value('baz', 2);
	$objects[0]->set_field_value('baz', 'meh');
	$objects[1]->set_field_value('baz', 1);
	$objects[1]->set_field_value('baz', 'feh');
    };
    $self->assert_str_equals('', $@);

    eval {
	$objects[0]->set_field_value('bar', 2);
    };
    $err = $@;
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($@));
    $self->assert_matches(qr/invalid value '2' specified for field 'bar' for class Dummy::Foo/, $err);

    eval {
	$objects[0]->set_field_value('bar', 'meh');
    };
    $err = $@;
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($err));
    $self->assert_matches(qr/invalid value 'meh' specified for field 'bar' for class Dummy::Foo/, $err);

    eval {
	$objects[1]->set_field_value('bar', 'blah');
    };
    $err = $@;
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($err));
    $self->assert_matches(qr/invalid value 'blah' specified for field 'bar' for class Dummy::Foo/, $err);
}

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

    my $foo = new Dummy::Foo();

    $foo->set_bar(34);
    $foo->set_baz('whatever');

    my $pk_val = $foo->save();

    $foo = new Dummy::Foo($pk_val);

    $self->assert_equals($foo->get_bar(), 34);
    $self->assert_equals($foo->get_baz(), 'whatever');

    $foo->set_bar(45);

    $foo->save();

    $foo = new Dummy::Foo($pk_val);

    $self->assert_equals($foo->get_bar(), 45);
    $self->assert_equals($foo->get_baz(), 'whatever');

    $foo->set_baz('something');
    $foo->save();

    $foo = new Dummy::Foo({ bar => 45 });

    $self->assert_equals($pk_val, $foo->get_pk_value());
    $self->assert_equals(45, $foo->get_bar());
    $self->assert_equals('something', $foo->get_baz());
}

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

    my $foo = new Dummy::Foo();

    $foo->set_bar(56);
    $foo->set_baz('So long, and thanks for all the fish!');

    my $pk_val = $foo->save();

    $foo = new Dummy::Foo($pk_val);
    $self->assert_equals($foo->get_bar(), 56);
    $self->assert_equals($foo->get_baz(), 'So long, and thanks for all the fish!');

    $foo->delete();

    $foo = new Dummy::Foo({ bar => 56 });

    $self->assert_null($foo->get_pk_value());
}

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

    my ($f, $b, $fz, $links) = populate_database();

    my $foo = Dummy::Foo->new({ foo => 3 });

    # NEW
    
    my $foreign_conditions = new PROP::Conditions::Foreign($links->[0], 'children');
    my $link_query = new PROP::Query::Link($foreign_conditions);

#    my $link_query = new PROP::Query::Link($links->[0], 'children');

    $self->assert(not defined $foo->get_children($links->[0]->get_table_name()));

    $foo->load_relatives([$link_query]);

    $self->assert_equals(4, scalar($foo->get_children($links->[0]->get_table_name())));
}

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

    my ($f, $b, $fz, $links) = populate_database();

    eval {
	$f->[0]->set_pk_value("meh");
    };
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($@));

    eval {
	$f->[0]->_add_parent("meh");
    };
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($@));

    eval {
	$f->[0]->_add_parent($links->[0], $b->[0]);
    };
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($@));

    eval {
	$b->[0]->_add_parent($links->[0], $f->[0]);
    };
    $self->assert_equals('', ref($@));

    eval {
	$f->[0]->_add_child("meh");
    };
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($@));

    eval {
	$f->[0]->_add_child($links->[0], $fz->[0]);
    };
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($@));

    eval {
	$f->[0]->_add_child($links->[0], $b->[0]);
    };
    $self->assert_equals('', ref($@));

    eval {
	$f->[0]->set_field_value('asdfzxcv');
    };
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($@));

    eval {
	$f->[0]->set_field_value('asdfzxcv', 34);
    };
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($@));

    eval {
	$f->[0]->load_relatives(['foo', 'bar', 'baz']);
    };
    $self->assert_equals('PROP::Exception::IllegalArgument', ref($@));

    
}

1;

=head1 Author

Andrew Gibbs (awgibbs@awgibbs.com,andrew.gibbs@nist.gov)

=head1 Legalese

This software was developed at the National Institute of Standards and
Technology by employees of the Federal Government in the course of
their official duties. Pursuant to title 17 Section 105 of the United
States Code this software is not subject to copyright protection and
is in the public domain. PROP is an experimental system. NIST
assumes no responsibility whatsoever for its use by other parties, and
makes no guarantees, expressed or implied, about its quality,
reliability, or any other characteristic. We would appreciate
acknowledgement if the software is used.  This software can be
redistributed and/or modified freely provided that any derivative
works bear some notice that they are derived from it, and any modified
versions bear some notice that they have been modified.
