The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use Test::More tests => 18;

package MyVal;

use Validation::Class;

# declare validation rules
mixin 'basic' => {
    required   => 1,
    min_length => 1,
    max_length => 255,
    filters    => [ 'lowercase', 'alphanumeric' ]
};

mixin 'validation' => {};

field 'login' => {
    mixin      => 'basic',
    label      => 'user login',
    error      => 'login invalid',
    validation => sub {
	my ( $self, $this, $fields ) = @_;
	return $this->{value} eq 'admin' ? 1 : 0;
    }
};

field 'password' => {
    mixin      => 'basic',
    label      => 'user password',
    error      => 'password invalid',
    validation => sub {
	my ( $self, $this, $fields ) = @_;
	return $this->{value} eq 'pass' ? 1 : 0;
    }
};

field 'something' => { mixin => [ 'basic', 'validation' ] };

package main;

# create instance
my $v = MyVal->new;
ok $v, 'instance created';

# verify fields received mixins
ok defined $v->fields->{login}->{required}
  && defined $v->fields->{login}->{min_length}
  && defined $v->fields->{login}->{max_length},
  'login field received mixin';
ok defined $v->fields->{password}->{required}
  && defined $v->fields->{password}->{min_length}
  && defined $v->fields->{password}->{max_length},
  'password field received mixin';

# check attributes
ok $v->params,  'params attr ok';
ok $v->fields,  'fields attr ok';

# ok $v->mixins,  'mixins attr ok'; - DEPRECATED
ok $v->proto->mixins,  'mixins attr ok';

# ok $v->filters, 'filters attr ok'; - DEPRECATED
ok $v->proto->filters, 'filters attr ok';

# ok $v->types,   'types attr ok'; - DEPRECATED
ok $v->proto->types,   'types attr ok';

# process field with multiple mixins
ok defined $v->fields->{something}->{required}
  && defined $v->fields->{something}->{min_length}
  && defined $v->fields->{something}->{max_length},
  'something field generated from multiple mixins';

# define grouped fields
$v->fields->{'auth.login'} = {
    mixin      => 'basic',
    label      => 'user login',
    error      => 'login invalid',
    validation => sub {
	my ( $self, $this, $fields ) = @_;
	return $this->{value} eq 'admin' ? 1 : 0;
      }
};

$v->fields->{'auth.password'} = {
    mixin      => 'basic',
    label      => 'user password',
    error      => 'password invalid',
    validation => sub {
	my ( $self, $this, $fields ) = @_;
	return $this->{value} eq 'pass' ? 1 : 0;
      }
};

$v->fields->{'user.name'} = {
    mixin      => 'basic',
    label      => 'user name',
    error      => 'invalid name',
    validation => sub {
	my ( $self, $this, $fields ) = @_;
	return 1;
      }
};

$v->fields->{'user.phone'} = {
    mixin      => 'basic',
    label      => 'user phone',
    error      => 'phone invalid',
    validation => sub {
	my ( $self, $this, $fields ) = @_;
	return 0;
      }
};

$v->fields->{'user.email'} = {
    mixin      => 'basic',
    label      => 'user email',
    error      => 'email invalid',
    validation => sub {
	my ( $self, $this, $fields ) = @_;
	return 1;
      }
};

package main;

my $params = {
    login        => 'admin1%^&%&^%^%&',
    password     => 'pass@@@#$#%$^',
    name         => 'al newkirk',
    phone        => '2155551212',
    email        => 'awncorp2cpan.org'
};

$v = MyVal->new( params => $params, fields => $v->fields );

# params set at new function
ok scalar( keys %{ $v->params } ), 'params have been set at instantiation';

# error class exists
ok !$v->error_count, 'error count reporting';

# validate login only
ok !$v->validate( { login => 'auth.login' } ), 'login field failed as expected';
ok $v->error_count == 1, 'error count accurate';
ok $v->errors_to_string eq 'login invalid',
  'error messages and error class to_string method works';

# check formatting
ok $v->params->{login}    eq 'admin1', 'login formatting worked';
ok $v->params->{password} eq 'pass',   'password formatting worked';

# process common password confirmation
$v->fields->{'password_cfm'} = {
    mixin_field => 'password',
    default	=> 'pass',
    validation  => sub {
	my ( $self, $this, $params ) = @_;
	return $this->{value} eq $params->{password} ? 1 : 0;
    }
};

$v = MyVal->new( params => $v->params, fields => $v->fields );

ok $v->validate('password'), 'password field validates';
ok $v->validate( 'password', 'password_cfm' ),
  'password confirmation validates';