The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use Test;

BEGIN { plan tests => 5 }

use lib qw(..);
use Data::Random qw( rand_chars );

use vars qw( %charsets );

%charsets = (
    all => [
        0 .. 9,
        'a' .. 'z',
        'A' .. 'Z',
        '#',
        ',',
        qw( ~ ! @ $ % ^ & * ( ) _ + = - { } | : " < > ? / . ' ; [ ] \ ` )
    ],
    alpha      => [ 'a' .. 'z',  'A' .. 'Z' ],
    upperalpha => [ 'A' .. 'Z' ],
    loweralpha => [ 'a' .. 'z' ],
    numeric    => [ 0 .. 9 ],
    alphanumeric => [ 0 .. 9, 'a' .. 'z', 'A' .. 'Z' ],
    misc         => [
        '#',
        ',',
        qw( ~ ! @ $ % ^ & * ( ) _ + = - { } | : " < > ? / . ' ; [ ] \ ` )
    ],
);

my %valid_chars;

foreach my $charset ( keys %charsets ) {
    @{ $valid_chars{$charset} }{ @{ $charsets{$charset} } } = ();
}

# Test default w/ no params -- should return one entry
{
    my $pass = 1;

    foreach my $charset ( keys %charsets ) {

        my $num_chars = @{ $charsets{$charset} };

        my $i = 0;
        while ( $pass && $i < $num_chars ) {
            my @chars = rand_chars( set => $charsets{$charset} );

            $pass = 0
              unless ( @chars == 1
                && exists( $valid_chars{$charset}->{ $chars[0] } ) );

            $i++;
        }

    }

    ok($pass);
}

# Test size option
{
    my $pass = 1;

    foreach my $charset ( keys %charsets ) {

        my $num_chars = @{ $charsets{$charset} };

        my $i = 0;
        while ( $pass && $i < $num_chars ) {
            my @chars = rand_chars( set => $charset, size => $i + 1 );

            $pass = 0 unless @chars == ( $i + 1 );

            foreach (@chars) {
                $pass = 0 unless exists( $valid_chars{$charset}->{$_} );
            }

            $i++;
        }

    }

    ok($pass);
}

# Test max/min option
{
    my $pass = 1;

    foreach my $charset ( keys %charsets ) {

        my $num_chars = @{ $charsets{$charset} };

        my $i = 0;
        while ( $pass && $i < $num_chars ) {
            my @chars = rand_chars(
                set => $charsets{$charset},
                min => $i,
                max => $num_chars
            );

            $pass = 0 unless ( @chars >= $i && @chars <= $num_chars );

            foreach (@chars) {
                $pass = 0 unless exists( $valid_chars{$charset}->{$_} );
            }

            $i++;
        }

    }

    ok($pass);
}

# Test size w/ min/max set
{
    my $pass = 1;

    foreach my $charset ( keys %charsets ) {

        my $num_chars = @{ $charsets{$charset} };

        my $i = 0;
        while ( $pass && $i < $num_chars ) {
            my @chars = rand_chars(
                set  => $charsets{$charset},
                size => $i + 1,
                min  => $i,
                max  => $num_chars
            );

            $pass = 0 unless @chars == ( $i + 1 );

            foreach (@chars) {
                $pass = 0 unless exists( $valid_chars{$charset}->{$_} );
            }

            $i++;
        }

    }

    ok($pass);
}

# Test w/ shuffle set to 0
{
    my $pass = 1;

    sub _get_index {
        my ( $charset, $char ) = @_;

        my $i = 0;
        while ( $charsets{$charset}->[$i] ne $char
            && $i < @{ $charsets{$charset} } )
        {
            $i++;
        }

        $i;
    }

    foreach my $charset ( keys %charsets ) {

        my $num_chars = @{ $charsets{$charset} };

        my $i = 0;
        while ( $pass && $i < $num_chars ) {
            my @chars =
              rand_chars( set => $charsets{$charset}, size => 2, shuffle => 0 );

            $pass = 0
              unless ( @chars == 2
                && _get_index( $charset, $chars[0] ) <
                _get_index( $charset, $chars[1] ) );

            foreach (@chars) {
                $pass = 0 unless exists( $valid_chars{$charset}->{$_} );
            }

            $i++;
        }

    }

    ok($pass);
}