use Test::More;

BEGIN
{
    $ENV{CLONE_CHOOSE_PREFERRED_BACKEND}
      and eval "use $ENV{CLONE_CHOOSE_PREFERRED_BACKEND}; 1;";
    $@ and plan skip_all => "No $ENV{CLONE_CHOOSE_PREFERRED_BACKEND} found.";
}

use Hash::Merge qw( merge );

my %left = (
    ss => 'left',
    sa => 'left',
    sh => 'left',
    as => ['l1', 'l2'],
    aa => ['l1', 'l2'],
    ah => ['l1', 'l2'],
    hs => {left => 1},
    ha => {left => 1},
    hh => {left => 1}
);

my %right = (
    ss => 'right',
    as => 'right',
    hs => 'right',
    sa => ['r1', 'r2'],
    aa => ['r1', 'r2'],
    ha => ['r1', 'r2'],
    sh => {right => 1},
    ah => {right => 1},
    hh => {right => 1}
);

# Test left precedence
Hash::Merge::set_behavior('LEFT_PRECEDENT');
my %lp = %{merge(\%left, \%right)};

is_deeply($lp{ss}, 'left', 'Left Precedent - Scalar on Scalar');
is_deeply($lp{sa}, 'left', 'Left Precedent - Scalar on Array');
is_deeply($lp{sh}, 'left', 'Left Precedent - Scalar on Hash');
is_deeply($lp{as}, ['l1', 'l2', 'right'], 'Left Precedent - Array on Scalar');
is_deeply($lp{aa}, ['l1', 'l2', 'r1', 'r2'], 'Left Precedent - Array on Array');
is_deeply($lp{ah}, ['l1', 'l2', 1], 'Left Precedent - Array on Hash');
is_deeply($lp{hs}, {left => 1}, 'Left Precedent - Hash on Scalar');
is_deeply($lp{ha}, {left => 1}, 'Left Precedent - Hash on Array');
is_deeply(
    $lp{hh},
    {
        left  => 1,
        right => 1
    },
    'Left Precedent - Hash on Hash'
);

Hash::Merge::set_behavior('RIGHT_PRECEDENT');
my %rp = %{merge(\%left, \%right)};

is_deeply($rp{ss}, 'right', 'Right Precedent - Scalar on Scalar');
is_deeply($rp{sa}, ['left', 'r1', 'r2'], 'Right Precedent - Scalar on Array');
is_deeply($rp{sh}, {right => 1}, 'Right Precedent - Scalar on Hash');
is_deeply($rp{as}, 'right', 'Right Precedent - Array on Scalar');
is_deeply($rp{aa}, ['l1', 'l2', 'r1', 'r2'], 'Right Precedent - Array on Array');
is_deeply($rp{ah}, {right => 1}, 'Right Precedent - Array on Hash');
is_deeply($rp{hs}, 'right', 'Right Precedent - Hash on Scalar');
is_deeply($rp{ha}, [1, 'r1', 'r2'], 'Right Precedent - Hash on Array');
is_deeply(
    $rp{hh},
    {
        left  => 1,
        right => 1
    },
    'Right Precedent - Hash on Hash'
);

Hash::Merge::set_behavior('STORAGE_PRECEDENT');
my %sp = %{merge(\%left, \%right)};

is_deeply($sp{ss}, 'left', 'Storage Precedent - Scalar on Scalar');
is_deeply($sp{sa}, ['left', 'r1', 'r2'], 'Storage Precedent - Scalar on Array');
is_deeply($sp{sh}, {right => 1}, 'Storage Precedent - Scalar on Hash');
is_deeply($sp{as}, ['l1', 'l2', 'right'], 'Storage Precedent - Array on Scalar');
is_deeply($sp{aa}, ['l1', 'l2', 'r1', 'r2'], 'Storage Precedent - Array on Array');
is_deeply($sp{ah}, {right => 1}, 'Storage Precedent - Array on Hash');
is_deeply($sp{hs}, {left  => 1}, 'Storage Precedent - Hash on Scalar');
is_deeply($sp{ha}, {left  => 1}, 'Storage Precedent - Hash on Array');
is_deeply(
    $sp{hh},
    {
        left  => 1,
        right => 1
    },
    'Storage Precedent - Hash on Hash'
);

Hash::Merge::set_behavior('RETAINMENT_PRECEDENT');
my %rep = %{merge(\%left, \%right)};

is_deeply($rep{ss}, ['left', 'right'], 'Retainment Precedent - Scalar on Scalar');
is_deeply($rep{sa}, ['left', 'r1', 'r2'], 'Retainment Precedent - Scalar on Array');
is_deeply(
    $rep{sh},
    {
        left  => 'left',
        right => 1
    },
    'Retainment Precedent - Scalar on Hash'
);
is_deeply($rep{as}, ['l1', 'l2', 'right'], 'Retainment Precedent - Array on Scalar');
is_deeply($rep{aa}, ['l1', 'l2', 'r1', 'r2'], 'Retainment Precedent - Array on Array');
is_deeply(
    $rep{ah},
    {
        l1    => 'l1',
        l2    => 'l2',
        right => 1
    },
    'Retainment Precedent - Array on Hash'
);
is_deeply(
    $rep{hs},
    {
        left  => 1,
        right => 'right'
    },
    'Retainment Precedent - Hash on Scalar'
);
is_deeply(
    $rep{ha},
    {
        left => 1,
        r1   => 'r1',
        r2   => 'r2'
    },
    'Retainment Precedent - Hash on Array'
);
is_deeply(
    $rep{hh},
    {
        left  => 1,
        right => 1
    },
    'Retainment Precedent - Hash on Hash'
);

Hash::Merge::specify_behavior(
    {
        SCALAR => {
            SCALAR => sub { $_[0] },
            ARRAY  => sub { $_[0] },
            HASH   => sub { $_[0] }
        },
        ARRAY => {
            SCALAR => sub { $_[0] },
            ARRAY  => sub { $_[0] },
            HASH   => sub { $_[0] }
        },
        HASH => {
            SCALAR => sub { $_[0] },
            ARRAY  => sub { $_[0] },
            HASH   => sub { $_[0] }
        }
    },
    "My Behavior"
);

my %cp = %{merge(\%left, \%right)};

is_deeply($cp{ss}, 'left', 'Custom Precedent - Scalar on Scalar');
is_deeply($cp{sa}, 'left', 'Custom Precedent - Scalar on Array');
is_deeply($cp{sh}, 'left', 'Custom Precedent - Scalar on Hash');
is_deeply($cp{as}, ['l1', 'l2'], 'Custom Precedent - Array on Scalar');
is_deeply($cp{aa}, ['l1', 'l2'], 'Custom Precedent - Array on Array');
is_deeply($cp{ah}, ['l1', 'l2'], 'Custom Precedent - Array on Hash');
is_deeply($cp{hs}, {left => 1}, 'Custom Precedent - Hash on Scalar');
is_deeply($cp{ha}, {left => 1}, 'Custom Precedent - Hash on Array');
is_deeply($cp{hh}, {left => 1}, 'Custom Precedent - Hash on Hash');

done_testing;
