### ----------------------------------------------------
### -- Iter::Able
### -- Licenses: Artistic-2.0
### -- Authors: 
### -- File: t/14-assign-at.rakutest
### ----------------------------------------------------
use Test;
use Iter::Able::Assign-At;

my &id = -> \g, \e, Str $desc? { g | e ~~ Seq:D ?? cmp-ok(g, "eqv", e, $desc) !! is-deeply(g, e, $desc) };

plan 30;

my $s;
$s := [0, 1, 2, 3];
id assign-at($s, 1 => -9), (0, -9, 2, 3).Seq, "Random list with 1 pair";

$s := (2, 2, 3, -4, 5);
id assign-at($s, 4 => 2, 0 => 5), (5, 2, 3, -4, 2).Seq, "Random list with 2 pairs";

$s := [];
id assign-at($s, 0 => 0), [].Seq,  "Empty list";

my $t = ();
id assign-at($t, 1 => 2), ().Seq,  "Empty itemized list";

$s := [0, 0, 0, 0];
id assign-at($s, (^$s X=> 7)), (7 xx $s), "All zeros with all indices filled";

$s := [6, 7, 8, 93, 51, 0, 4, -3, 64];
id assign-at($s, $s.Int => 0), $s.Seq, "Random list with out-of-bounds index";

$s := [4, 5, 6].Seq;
id $s.&assign-at([1 => 3, 0 => 1]), [1, 3, 6].Seq, "Two pairs passed as a single Array";

$s := [4, 5, 6].lazy;
my \out = $s.&assign-at([1 => 3, 0 => 1]);
ok out.is-lazy;
id out.eager, (1, 3, 6), "Explicitly .lazy input";

$s := [1, 2, 3];
id assign-at($s, -1 => 100, 0 => 4), (4, 2, 100).Seq, "Negative index assignment on an iterable";

$s := [1, 2, 3];
id assign-at($s, -133 => 100, 0 => 5), (5, 2, 3).Seq, "Negative index assignment on an iterable (out of bounds)";

$s := "Real";
id assign-at($s, 0 => "r"), "real", "String with 1 pair";

$s := "mode";
id assign-at($s, 0 => "r", 2 => "p"), "rope", "String with 2 pairs";

$s := "Real";
id assign-at($s, 0 => "R", 2 => "P", 12 => "z"), "RePl", "String with 3 pairs, but 1 out of bounds";

$s := "no";
id assign-at($s, 0 => "zo"), "zoo", "String with an expanding-pair at 0";

$s := "yearly";
id assign-at($s, 3 => "ZZZ"), "yeaZZZly", "String with an expanding-pair in the middle";

$s := "no";
id $s.&assign-at(1 => ""), "n", "String with a remover pair";

$s := "fried";
id assign-at($s, 2 => "", 4 => "ddy"), "freddy", "String with a remover pair and an expanding pair";

$s := "fried";
id assign-at($s, 0 => "", 1 => "fr", 3 => "e", 491 => "eh"), "fried", "String with remover, expander, replacer, out of bounds pairs";

$s := "yes";
id assign-at($s, -1 => "\$", 0 => "z"), "ze\$", "Negative index assignment on a string";

$s := "yes";
id assign-at($s, -182 => "\$", 0 => "z"), "zes", "Negative index assignment on a string (out of bounds)";

$s := (0, -2, -7, 5, 13, 22);
my \it = $s.iterator;
it.pull-one for ^2;
my \newit = assign-at(it, 1 => 300, 8 => 900);
it.pull-one;  # should affect `newit`s behaviour
does-ok newit, Iterator, "Iterator (returned an Iterator, not a Seq)";
id Seq.new(newit), [5, 300, 22].Seq, "Iterator (values)";
ok it.pull-one =:= IterationEnd, "Iterator (original, exhausted)";
ok newit.pull-one =:= IterationEnd, "Iterator (new, exhausted)";

# Invalid calls
throws-like { [].&assign-at }, Exception, "No pair", message => /:i 'Must pass at least one pair' /;
throws-like { [].&assign-at(^Inf X=> 1) }, Exception, "Possibly nonfinite number of pairs", message => /:i 'lazy' /;
throws-like { "".&assign-at(*) }, Exception, "Nonpair translator", message => /:i 'should all be pairs' /;
throws-like { "".&assign-at("yes" => 4) }, Exception, "Noninteger key-having translator", message => /:i 'keys should be all integers' /;
throws-like { [1].lazy.&assign-at(-1 => 0) }, Exception, "Negative index on a lazy array", message => /:i 'negative indexes on a possibly lazy iterable' /;

done-testing;


