use v6.d;

use Test;

plan 80;


=begin description

This tests some mixed multi-dimensional structures.

NOTE:
These tests don't go any more than two levels deep
(AoH, AoP) in most cases.

When we have this support, then
this test should be added too more.

Some deeper tests were already added.

=end description

# UNSPECCED
{ # Array of Pairs
    my @array;
    isa-ok(@array, Array);

    my $pair = ('key' => 'value');
    isa-ok($pair, Pair);

    @array[0] = $pair; # assign a variable
    is(+@array, 1, 'the array has one value in it');

    isa-ok(@array[0], Pair);
    is(@array[0]<key>, 'value', 'got the right pair value');

    @array[1] = ('key1' => 'value1'); # assign it inline
    is(+@array, 2, 'the array has two values in it');
    isa-ok(@array[1], Pair);

    is(@array[1]<key1>, 'value1', 'got the right pair value');
}

# UNSPECCED
{ # Array of Hashes
    my @array;
    isa-ok(@array, Array);

    my %hash = ('key', 'value', 'key1', 'value1');
    isa-ok(%hash, Hash);
    is(+%hash.keys, 2, 'our hash has two keys');

    @array[0] = %hash;
    is(+@array, 1, 'the array has one value in it');
    isa-ok(@array[0], Hash);
    is(@array[0]{"key"}, 'value', 'got the right value for key');
    is(@array[0]<key1>, 'value1', 'got the right value1 for key1');
}

{ # Array of Arrays
    # L<S09/Multidimensional arrays>
    my @array = (1, [2, 3], [4, 5], 6);
    isa-ok(@array, Array);

    is(+@array, 4, 'got 4 elements in the Array of Arrays');
    is(@array[0], 1, 'got the right first element');
    isa-ok(@array[1], Array);
    is(@array[1][0], 2, 'got the right second/first element');
    is(@array[1][1], 3, 'got the right second/second element');
    isa-ok(@array[2], Array);
    is(@array[2][0], 4, 'got the right third/first element');
    is(@array[2][1], 5, 'got the right third/second element');
    is(@array[3], 6, 'got the right fourth element');
}

# UNSPECCED
{ # Array of Subs
    my @array;
    isa-ok(@array, Array);

    @array[0] = sub { 1 };
    @array[1] = { 2 };
    @array[2] = -> { 3 };

    is(+@array, 3, 'got three elements in the Array');
    isa-ok(@array[0], Sub);
    isa-ok(@array[1], Block);
    isa-ok(@array[2], Block);

    is(@array[0](), 1, 'the first element (when executed) is 1');
    is(@array[1](), 2, 'the second element (when executed) is 2');
    is(@array[2](), 3, 'the third element (when executed) is 3');
}

# UNSPECCED
{ # Hash of Arrays
    my %hash;
    isa-ok(%hash, Hash);

    %hash<key> = [ 1, 2, 3 ];
    isa-ok(%hash<key>, Array);

    is(+%hash<key>, 3, 'it should have 3 values in it');
    is(%hash<key>[0], 1, 'got the right value');
    is(%hash<key>[1], 2, 'got the right value');
    is(%hash<key>[2], 3, 'got the right value');

    {
        my $array = %hash<key>;
        is(+$array, 3, 'it should have 3 values in it');
        is($array[0], 1, 'got the right value (when I pull the array out)');
        is($array[1], 2, 'got the right value (when I pull the array out)');
        is($array[2], 3, 'got the right value (when I pull the array out)');
    }

{
    %hash<key>.push(4);
    is(+%hash<key>, 4, 'it should now have 4 values in it');
    is(%hash<key>[3], 4, 'got the right value (which we just pushed onto the list)');
}

}


{ # Hash of Array-refs
  # UNSPECCED
    my %hash;
    isa-ok(%hash, Hash);

    my @array = ( 1, 2, 3 );
    isa-ok(@array, Array);

    %hash<key> = @array;
    isa-ok(%hash<key>, Array);

    is(+%hash<key>, 3, 'it should have 3 values in it');
    is(%hash<key>[0], 1, 'got the right value');
    is(%hash<key>[1], 2, 'got the right value');
    is(%hash<key>[2], 3, 'got the right value');

    {
        my @array = @( %hash<key> );
        is(+@array, 3, 'it should have 3 values in it');
        is(@array[0], 1, 'got the right value (when I pull the array out)');
        is(@array[1], 2, 'got the right value (when I pull the array out)');
        is(@array[2], 3, 'got the right value (when I pull the array out)');
    }

{
    %hash<key>.push(4);

    is(+%hash<key>, 4, 'it should now have 4 values in it');
    is(%hash<key>[3], 4, 'got the right value (which we just pushed onto the array)');
}

}

{ # Itemized hash survives addition to an array.
  my %h = <a 5 b 6>;
  my $hr = %h;
  my $a0 = [ $%h ,'extra' ];
  my $a1 = [ $%h ];
  my $a2 = [ $hr ];
  is($a0.elems,2,'itemized hash should not get decomposed');
  is($a1.elems,1,'itemized hash should not get decomposed');
  is($a2.elems,1,'itemized hash should not get decomposed');
}

{ # nested, declared in one statement
    my $h = { a => [ 1,2,3 ] };
    isa-ok($h<a>.WHAT, Array, "array nested in hashref in one declaration");
}

{ # structures deeper than 2 levels
    my @array;
    @array[0][0][0][0][0] = 5;
    isa-ok(@array, Array);
    isa-ok(@array[0], Array);
    isa-ok(@array[0][0], Array);
    isa-ok(@array[0][0][0], Array);
    isa-ok(@array[0][0][0][0], Array);
    is(@array[0][0][0][0][0], 5, "5 level deep arrays only structure");

    @array[1]<two>[0]<four>[0]<six> = 6;
    isa-ok(@array, Array);
    isa-ok(@array[1], Hash);
    isa-ok(@array[1]<two>, Array);
    isa-ok(@array[1]<two>[0], Hash);
    is(+@array[1]<two>[0], 1, "one key at level 4");
    isa-ok(@array[1]<two>[0]<four>, Array);
    isa-ok(@array[1]<two>[0]<four>[0], Hash);
    is(@array[1]<two>[0]<four>[0]<six>, 6, "6 level deep mixed structure");


    @array[2]<two>[0]<f><other> = 5;
    isa-ok(@array[1]<two>[0], Hash);
    #?rakudo todo 'isa hash'
    isa-ok(@array[1]<two>[0]<f>, Hash);
    #?rakudo 2 todo 'unknown'
    is(+@array[1]<two>[0], 2, "two keys at level 4");
    is(@array[1]<two>[0]<f><other>, 5, "more keys at level 4");
}

# vim: ft=perl6
