#!perl -w
# $Id: 00_regression.t,v 1.5 2008/07/25 13:25:47 drhyde Exp $

use strict;

use Test::More tests => 19;

use Sort::MultipleFields qw(mfsort mfsortmaker);

my $library = [
    { author => 'Hoyle',  title => 'Black Cloud, The' },
    { author => 'Clarke', title => 'Rendezvous with Rama' },
    { author => 'Clarke', title => 'Prelude to Space' },
    { author => 'Clarke', title => 'Islands In The Sky' },
    { author => 'Asimov', title => 'Pebble in the Sky' },
    { author => 'Asimov', title => 'Foundation' },
    { author => 'Asimov', title => 'David Starr, Space Ranger' }
];
my $numbers = [map { { value => $_ } } qw(100 10 1 11)];

# shortcut aliases
is_deeply(
    scalar(mfsort(sub { author => 'aSc' }, $library)),
    scalar(mfsort(sub { author => 'ascEnding' }, @{$library})),
    "asc == ascending (case-insensitively)"
);
is_deeply(
    scalar(mfsort(sub { author => 'desC' }, $library)),
    scalar(mfsort(sub { author => 'deScending' }, @{$library})),
    "desc == descending (case-insensitively)"
);
is_deeply(
    scalar(mfsort(sub { value => 'numasC' }, $numbers)),
    scalar(mfsort(sub { value => 'nuMascending' }, $numbers)),
    "numasc == numascending (case-insensitively)"
);
is_deeply(
    scalar(mfsort(sub { value => 'numdesC' }, $numbers)),
    scalar(mfsort(sub { value => 'nuMdescending' }, $numbers)),
    "numdesc == numdescending (case-insensitively)"
);

# list/scalar input/output
my @foo = mfsort sub { author => 'desc' }, $library;
ok(@foo == 7, "returns a list in list context");
ok(ref(scalar(mfsort(sub { author => 'desc' }, $library))),
    "returns a ref in scalar context");
is_deeply(
    scalar(mfsort(sub { author => 'asc' }, $library)),
    scalar(mfsort(sub { author => 'asc' }, @{$library})),
    "Records can be listref or list, makes no difference"
);

# shortcuts sort correctly
is_deeply(
    [map { $_->{author} } mfsort(sub { author => 'asc' }, $library)],
    [reverse qw(Hoyle Clarke Clarke Clarke Asimov Asimov Asimov)],
    'asc sorts text correctly'
);
is_deeply(
    [map { $_->{author} } mfsort(sub { author => 'desc' }, $library)],
    [qw(Hoyle Clarke Clarke Clarke Asimov Asimov Asimov)],
    'desc sorts text correctly'
);
is_deeply(
    [map { $_->{value} } mfsort(sub { value => 'asc' }, $numbers)],
    [qw(1 10 100 11)],
    "asc sorts numbers ASCIIbetically"
);
is_deeply(
    [map { $_->{value} } mfsort(sub { value => 'desc' }, $numbers)],
    [reverse qw(1 10 100 11)],
    "desc sorts numbers ASCIIbetically"
);

is_deeply(
    [map { $_->{value} } mfsort(sub { value => 'numasc' }, $numbers)],
    [qw(1 10 11 100)],
    "numasc sorts numerically"
);
is_deeply(
    [map { $_->{value} } mfsort(sub { value => 'numdesc' }, $numbers)],
    [reverse qw(1 10 11 100)],
    "numdesc sorts numerically"
);

# sort function instead of shortcut
is_deeply(
    [map { $_->{author} } mfsort(
        # this should sort C, then H, then A
        sub { author => sub {
            return -1 if($_[0] =~ '^C');
            return  1 if($_[1] =~ '^C');
            return  1 if($_[0] =~ '^A');
            return -1 if($_[1] =~ '^A');
            return  0;
        } },
        $library
    )],
    [qw(Clarke Clarke Clarke Hoyle Asimov Asimov Asimov)],
    'user-supplied sort function works'
);

is_deeply(
    [mfsort sub { author => 'asc', title => 'asc' }, $library],
    [
        { author => 'Asimov', title => 'David Starr, Space Ranger' },
        { author => 'Asimov', title => 'Foundation' },
        { author => 'Asimov', title => 'Pebble in the Sky' },
        { author => 'Clarke', title => 'Islands In The Sky' },
        { author => 'Clarke', title => 'Prelude to Space' },
        { author => 'Clarke', title => 'Rendezvous with Rama' },
        { author => 'Hoyle',  title => 'Black Cloud, The' },
    ],
    "two-field sort works"
);

is_deeply(
    # sort by author, title, and reverse publication date
    [mfsort sub { author => 'asc', title => 'asc', year => 'desc' }, [
        # unsort the input ...
        sort {
            rand() < 0.5 ? -1 : 1
        } map {
            { %{$_}, year => 2001 },
            { %{$_}, year => 2002 },
            { %{$_}, year => 2003 },
        } @{$library}
    ]],
    [
        map {
            { %{$_}, year => 2003 },
            { %{$_}, year => 2002 },
            { %{$_}, year => 2001 },
        } mfsort sub {
            author => 'asc', title => 'asc'
        },  $library
    ],
    "three-field sort works"
);

my $crazysort = sub {
    author => 'asc',
    title => 'asc',
    year => 'desc',
    colour => sub { 
        my @in = map {
            $_ eq 'red'    ? 0 :
            $_ eq 'orange' ? 1 :
            $_ eq 'yellow' ? 2 :
            $_ eq 'green'  ? 3 :
            $_ eq 'blue'   ? 4 :
            $_ eq 'indigo' ? 5 :
                             6
        } @_;
        $in[0] <=> $in[1];
    }
};
my $crazyinput = [
    sort {
        rand() < 0.5 ? -1 : 1
    } map {
        { %{$_}, year => 2001 },
        { %{$_}, year => 2002 },
        { %{$_}, year => 2003 },
    } map {
        my $in = $_;
        map { { %{$in}, colour => $_ } }
            qw(red orange yellow green blue indigo violet)
    } @{$library}
];
my $crazyoutput = [
    map {
        my $in = $_;
        map { { %{$in}, colour => $_ } }
            qw(red orange yellow green blue indigo violet)
    } map {
        { %{$_}, year => 2003 },
        { %{$_}, year => 2002 },
        { %{$_}, year => 2001 },
    } mfsort sub {
        author => 'asc', title => 'asc'
    }, $library
];
is_deeply(
    # sort by author, title, reverse publication date, and colour(!)
    [mfsort \&{$crazysort}, $crazyinput],
    $crazyoutput,
    "four-field sort works, including a Mad Sort"
);

# sort function instead of shortcut
my $usersupplied = mfsortmaker(sub {
    author => sub {
        return -1 if($_[0] =~ '^C');
        return  1 if($_[1] =~ '^C');
        return  1 if($_[0] =~ '^A');
        return -1 if($_[1] =~ '^A');
        return  0;
    }
});
is_deeply(
    [map { $_->{author} } sort $usersupplied @{$library}],
    [qw(Clarke Clarke Clarke Hoyle Asimov Asimov Asimov)],
    'mfsortmaker works'
);

$crazysort = mfsortmaker($crazysort);
is_deeply(
    # sort by author, title, reverse publication date, and colour(!)
    [sort $crazysort @{$crazyinput}],
    $crazyoutput,
    "mfsortmaker even works for a really crazy sort spec"
);