#! /usr/bin/env perl

use strict;
use warnings;

use Test::More;
use Test::Deep;
use Data::DPath 'dpath', 'dpathr';
use Data::Dumper;

# local $Data::DPath::DEBUG = 1;

BEGIN {
        if ($] < 5.010) {
                plan skip_all => "Perl 5.010 required for the smartmatch overloaded tests. This is ".$];
        }
}

use_ok( 'Data::DPath' );

my $data = {
            AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                      RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                      DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                    },
            some => { where => { else => {
                                          AAA => { BBB => { CCC => 'affe' } },
                                         } } },
            strange_keys => { 'DD DD' => { 'EE/E' => { CCC => 'zomtec' } } },
           };

my @resultlist;
my $resultlist;
my $context;

# trivial matching

@resultlist = dpath('/AAA/BBB/CCC')->match($data);
cmp_bag(\@resultlist, [ ['XXX', 'YYY', 'ZZZ'] ], "KEYs" );

@resultlist = dpathr('/AAA/BBB/CCC')->match($data);
cmp_bag(\@resultlist, [ \($data->{AAA}{BBB}{CCC}) ], "KEYs (REFERENCES)" );

@resultlist = dpath('/AAA/./BBB/./CCC')->match($data);
cmp_bag(\@resultlist, [ ['XXX', 'YYY', 'ZZZ'] ], "KEYs + NOSTEPs" );

@resultlist = dpathr('/AAA/./BBB/./CCC')->match($data);
cmp_bag(\@resultlist, [ \($data->{AAA}{BBB}{CCC}) ], "KEYs + NOSTEPs (REFERENCES)" );

@resultlist = dpath('/AAA/BBB/CCC/..')->match($data);
cmp_bag(\@resultlist, [ { CCC => ['XXX', 'YYY', 'ZZZ'] } ], "KEYs + PARENT" );

@resultlist = dpathr('/AAA/BBB/CCC/..')->match($data);
cmp_bag(\@resultlist, [ \($data->{AAA}{BBB}) ], "KEYs + PARENT (REFERENCES)" );

@resultlist = dpath('/AAA/BBB/CCC/../.')->match($data);
cmp_bag(\@resultlist, [ { CCC => ['XXX', 'YYY', 'ZZZ'] } ], "KEYs + PARENT + NOSTEP" );

@resultlist = dpath('//../CCC')->match($data);
#print Dumper(\@resultlist);
cmp_bag(\@resultlist, [ [ qw/ XXX YYY ZZZ / ],
                          [ qw/ RR1 RR2 RR3 / ],
                          'affe',                      # missing due to reduction to HASH|ARRAY in _any?
                          'zomtec',
                        ], "KEYs + PARENT + ANYWHERE" );

# here only CCC that is 2 levels above leafs are expected, affe/zomtec do not match for a valid reason
@resultlist = dpath('//../../CCC')->match($data);
#print Dumper(\@resultlist);
cmp_bag(\@resultlist, [ [ qw/ XXX YYY ZZZ / ],
                          [ qw/ RR1 RR2 RR3 / ],
                        ], "KEYs + TOO MANY PARENT + ANYWHERE" );

@resultlist = dpath('//./.././CCC/.')->match($data);
#print Dumper(\@resultlist);
cmp_bag(\@resultlist, [ [ qw/ XXX YYY ZZZ / ],
                          [ qw/ RR1 RR2 RR3 / ],
                          'affe',                      # missing due to reduction to HASH|ARRAY in _any?
                          'zomtec',
                        ], "KEYs + PARENT + ANYWHERE + NOSTEP" );

@resultlist = dpath('/AAA/BBB/CCC/../..')->match($data);
cmp_bag(\@resultlist, [
                         {
                          BBB => { CCC => ['XXX', 'YYY', 'ZZZ'] },
                          RRR => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                          DDD => { EEE => [ qw/ uuu vvv www / ] },
                         }
                        ], "KEYs + PARENT + PARENT" );

@resultlist = dpathr('/AAA/BBB/CCC/../..')->match($data);
cmp_bag(\@resultlist, [ \($data->{AAA}) ], "KEYs + PARENT + PARENT (REFERENCES)" );

@resultlist = dpath('/AAA/././././BBB/./CCC/../././../././.')->match($data);
cmp_bag(\@resultlist, [
                         {
                          BBB => { CCC => ['XXX', 'YYY', 'ZZZ'] },
                          RRR => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                          DDD => { EEE => [ qw/ uuu vvv www / ] },
                         }
                        ], "KEYs + PARENT + PARENT + NOSTEPs" );

@resultlist = dpath('/AAA/BBB/CCC/../../DDD')->match($data);
cmp_bag(\@resultlist, [ { EEE => [ qw/ uuu vvv www / ] } ], "KEYs + PARENT + KEY" );

@resultlist = dpath('/AAA/*/CCC/../../DDD')->match($data);
cmp_bag(\@resultlist, [ { EEE => [ qw/ uuu vvv www / ] } ], "KEYs + ANYSTEP + PARENT + KEY no double results" );

# -------------------- ::ancestor --------------------

@resultlist = dpath('/AAA/BBB/CCC/::ancestor')->match($data);
cmp_deeply(\@resultlist, [
                          # order matters!
                          { CCC  => [ qw/ XXX YYY ZZZ / ] },
                          {
                           BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                           RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                           DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                          },
                          {
                           AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                                     RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                                     DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                                   },
                           some => { where => { else => {
                                                         AAA => { BBB => { CCC => 'affe' } },
                                                        } } },
                           strange_keys => { 'DD DD' => { 'EE/E' => { CCC => 'zomtec' } } },
                          },
                         ], "KEYs + ANCESTOR" );

@resultlist = dpath('/AAA/BBB/CCC/::ancestor[0]')->match($data);
cmp_deeply(\@resultlist, [
                          { CCC  => [ qw/ XXX YYY ZZZ / ] },
                         ], "KEYs + ANCESTOR + FILTER int 0" );

@resultlist = dpath('/AAA/BBB/CCC/::ancestor[1]')->match($data);
cmp_deeply(\@resultlist, [
                          {
                           BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                           RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                           DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                          },
                         ], "KEYs + ANCESTOR + FILTER int 1" );

@resultlist = dpath('/AAA/BBB/CCC/::ancestor[2]')->match($data);
cmp_deeply(\@resultlist, [
                          {
                           AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                                     RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                                     DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                                   },
                           some => { where => { else => {
                                                         AAA => { BBB => { CCC => 'affe' } },
                                                        } } },
                           strange_keys => { 'DD DD' => { 'EE/E' => { CCC => 'zomtec' } } },
                          },
                         ], "KEYs + ANCESTOR + FILTER int 2" );

@resultlist = dpath('/AAA/BBB/CCC/::ancestor[3]')->match($data);
cmp_deeply(\@resultlist, [ ], "KEYs + ANCESTOR + FILTER int outofbound" );

# -------------------- ::ancestor-or-self --------------------

@resultlist = dpath('/AAA/BBB/CCC/::ancestor-or-self')->match($data);
cmp_deeply(\@resultlist, [
                          # order matters!
                          [ qw/ XXX YYY ZZZ / ],
                          { CCC  => [ qw/ XXX YYY ZZZ / ] },
                          {
                           BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                           RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                           DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                          },
                          {
                           AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                                     RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                                     DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                                   },
                           some => { where => { else => {
                                                         AAA => { BBB => { CCC => 'affe' } },
                                                        } } },
                           strange_keys => { 'DD DD' => { 'EE/E' => { CCC => 'zomtec' } } },
                          },
                         ], "KEYs + ANCESTOR_OR_SELF" );

@resultlist = dpath('/AAA/BBB/CCC/::ancestor-or-self[0]')->match($data);
cmp_deeply(\@resultlist, [
                          [ qw/ XXX YYY ZZZ / ],
                         ], "KEYs + ANCESTOR_OR_SELF + FILTER int 0" );

@resultlist = dpath('/AAA/BBB/CCC/::ancestor-or-self[1]')->match($data);
cmp_deeply(\@resultlist, [
                          { CCC  => [ qw/ XXX YYY ZZZ / ] },
                         ], "KEYs + ANCESTOR_OR_SELF + FILTER int 1" );

@resultlist = dpath('/AAA/BBB/CCC/::ancestor-or-self[2]')->match($data);
cmp_deeply(\@resultlist, [
                          {
                           BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                           RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                           DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                          },
                         ], "KEYs + ANCESTOR_OR_SELF + FILTER int 2" );

@resultlist = dpath('/AAA/BBB/CCC/::ancestor-or-self[3]')->match($data);
cmp_deeply(\@resultlist, [
                          {
                           AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                                     RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                                     DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                                   },
                           some => { where => { else => {
                                                         AAA => { BBB => { CCC => 'affe' } },
                                                        } } },
                           strange_keys => { 'DD DD' => { 'EE/E' => { CCC => 'zomtec' } } },
                          },
                         ], "KEYs + ANCESTOR_OR_SELF + FILTER int 3" );

@resultlist = dpath('/AAA/BBB/CCC/::ancestor-or-self[4]')->match($data);
cmp_deeply(\@resultlist, [ ], "KEYs + ANCESTOR_OR_SELF + FILTER int outofbound" );

@resultlist = dpath('/AAA/BBB/CCC/"::ancestor-or-self"')->match($data);
cmp_deeply(\@resultlist, [ ], "KEYs + quoted ANCESTOR_OR_SELF" );

# -------------------- misc --------------------

@resultlist = dpath('/')->match($data);
cmp_bag(\@resultlist, [ $data ], "ROOT" );

@resultlist = dpath('/AAA/*/CCC')->match($data);
cmp_bag(\@resultlist, [ ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "KEYs + ANYSTEP" );

# --- same with operator ---

cmp_bag($data ~~ dpath('/AAA/BBB/CCC'),    [ ['XXX', 'YYY', 'ZZZ'] ], "KEYs" );
cmp_bag($data ~~ dpath('/AAA/BBB/CCC/..'), [ { CCC => ['XXX', 'YYY', 'ZZZ'] } ], "KEYs + PARENT" );
cmp_bag($data ~~ dpath('/AAA/BBB/CCC/../..'), [
                                                 {
                                                  BBB => { CCC => ['XXX', 'YYY', 'ZZZ'] },
                                                  RRR => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                                                  DDD => { EEE => [ qw/ uuu vvv www / ] },
                                                 }
                                                ], "KEYs + PARENT + PARENT" );
cmp_bag($data ~~ dpath('/AAA/BBB/CCC/../../DDD'), [ { EEE => [ qw/ uuu vvv www / ] } ], "KEYs + PARENT + KEY" );
cmp_bag($data ~~ dpath('/AAA/*/CCC/../../DDD'), [ { EEE => [ qw/ uuu vvv www / ] } ], "KEYs + ANYSTEP + PARENT + KEY no double results" );
cmp_bag($data ~~ dpath('/'), [ $data ], "ROOT" );
cmp_bag($data ~~ dpath('/AAA/*/CCC'), [ ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "KEYs + ANYSTEP" );

# --- ---

@resultlist = dpath('//AAA/*/CCC')->match($data);
cmp_bag(\@resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], ['RR1', 'RR2', 'RR3'] ], "ANYWHERE + KEYs + ANYSTEP" );
@resultlist = dpath('///AAA/*/CCC')->match($data);
cmp_bag(\@resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], ['RR1', 'RR2', 'RR3'] ], "2xANYWHERE + KEYs + ANYSTEP" );


@resultlist = Data::DPath->match($data, '//AAA/*/CCC');
cmp_bag(\@resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "ANYWHERE + KEYs + ANYSTEP as function" );
@resultlist = Data::DPath->match($data, '///AAA/*/CCC');
cmp_bag(\@resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "2xANYWHERE + KEYs + ANYSTEP as function" );

# from now on more via Perl 5.10 smart matching

# --------------------

$resultlist = $data ~~ dpath '/some//CCC';
cmp_bag($resultlist, [ 'affe' ], "ROOT + ANYWHERE + KEY + KEY" );

$resultlist = $data ~~ dpath '//some//CCC';
cmp_bag($resultlist, [ 'affe' ], "ANYWHERE + KEY + ANYWHERE + KEY" );

$resultlist = $data ~~ dpath '/some//else//CCC';
cmp_bag($resultlist, [ 'affe' ], "ROOT + KEY + ANYWHEREs + KEY" );

$resultlist = $data ~~ dpath '//some//else//CCC';
cmp_bag($resultlist, [ 'affe' ], "ANYWHERE + KEYs + ANYWHEREs" );

$resultlist = $data ~~ dpathr '//some//else//CCC';
cmp_bag($resultlist, [ \($data->{some}{where}{else}{AAA}{BBB}{CCC}) ], "ANYWHERE + KEYs + ANYWHEREs (REFERENCES)" );

# --------------------

my $dpath = dpath('//AAA/*/CCC');
$resultlist = $data ~~ $dpath;
cmp_bag($resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "ANYWHERE + KEYs + ANYSTEP with smartmatch and variable" );
$dpath = dpath('///AAA/*/CCC');
$resultlist = $data ~~ $dpath;
cmp_bag($resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "2xANYWHERE + KEYs + ANYSTEP with smartmatch and variable" );

$resultlist = $data ~~ dpath('//AAA/*/CCC');
cmp_bag($resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "ANYWHERE + KEYs + ANYSTEP with smartmatch and dpath()" );
$resultlist = $data ~~ dpath('///AAA/*/CCC');
cmp_bag($resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "2xANYWHERE + KEYs + ANYSTEP with smartmatch and dpath()" );

$resultlist = $data ~~ dpathr('///AAA/*/CCC');
cmp_bag($resultlist, [ \($data->{some}{where}{else}{AAA}{BBB}{CCC}),
                       \($data->{AAA}{BBB}{CCC}),
                       \($data->{AAA}{RRR}{CCC}),
                     ], "2xANYWHERE + KEYs + ANYSTEP with smartmatch and dpath() (REFERENCES)" );

$resultlist = $data ~~ dpath('//AAA');
cmp_bag($resultlist, [
                      {
                       BBB => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                       RRR => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                       DDD => { EEE  => [ qw/ uuu vvv www / ] },
                      },
                      { BBB => { CCC => 'affe' } },
                     ], "ANYWHERE + KEY" );

$resultlist = $data ~~ dpath('//AAA/*');
cmp_bag($resultlist, [
                      { CCC  => [ qw/ XXX YYY ZZZ / ] },
                      { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                      { EEE  => [ qw/ uuu vvv www / ] },
                      { CCC => 'affe' },
                     ], "ANYWHERE + KEY + ANYSTEP" );

$resultlist = $data ~~ dpath('//AAA/*[size == 3]');
cmp_bag($resultlist, [ ], "ANYWHERE + KEY + ANYSTEP + FILTER size" );

$resultlist = $data ~~ dpath('//AAA[size == 3]');
cmp_bag($resultlist, [
                      { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                        RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                        DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                      }
                     ], "ANYWHERE + KEY + FILTER size == 3" );

$resultlist = $data ~~ dpath('//AAA[size != 3]');
cmp_bag($resultlist, [
                      { BBB => { CCC => 'affe' } }
                     ], "ANYWHERE + KEY + FILTER size != 3" );

$resultlist = $data ~~ dpath('//AAA/*/*[size == 3]');
cmp_bag($resultlist, [
                      [ qw/ XXX YYY ZZZ / ],
                      [ qw/ RR1 RR2 RR3 / ],
                      [ qw/ uuu vvv www / ],
                     ], "ANYWHERE + KEY + ANYSTEP + FILTER size" );

$resultlist = $data ~~ dpath('//.[size == 3]');
cmp_bag($resultlist, [
                      $data,
                      $data->{AAA},
                      [ qw/ XXX YYY ZZZ / ],
                      [ qw/ RR1 RR2 RR3 / ],
                      [ qw/ uuu vvv www / ],
                     ], "ANYWHERE + FILTER size" );

$resultlist = $data ~~ dpath('//AAA/*[size == 1]');
cmp_bag($resultlist, [
                      { CCC  => [ qw/ XXX YYY ZZZ / ] },
                      { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                      { EEE  => [ qw/ uuu vvv www / ] },
                      { CCC => 'affe' },
                     ], "ANYWHERE + KEY + ANYSTEP + FILTER size" );

$resultlist = $data ~~ dpath '//AAA/*/CCC';
cmp_bag($resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "ANYWHERE + KEYs + ANYSTEP with smartmatch and dpath without parens" );
$resultlist = $data ~~ dpath '///AAA/*/CCC';
cmp_bag($resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "2xANYWHERE + KEYs + ANYSTEP with smartmatch and dpath without parens" );

$resultlist = $data ~~ dpath '//AAA/*/CCC';
cmp_bag($resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "ANYWHERE + KEYs + ANYSTEP with smartmatch and dpath without parens commutative" );
$resultlist = $data ~~ dpath '///AAA/*/CCC';
cmp_bag($resultlist, [ 'affe', ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], "2xANYWHERE + KEYs + ANYSTEP with smartmatch and dpath without parens commutative" );

$resultlist = $data ~~ dpath '/AAA/*/CCC/*';
cmp_bag($resultlist, [ 'XXX', 'YYY', 'ZZZ', 'RR1', 'RR2', 'RR3' ], "trailing .../* unpacks" );

$resultlist = $data ~~ dpath '/strange_keys/DD DD/"EE/E"/CCC';
$resultlist = $data ~~ dpath '/strange_keys/"DD DD"/"EE/E"/CCC';
cmp_bag($resultlist, [ 'zomtec' ], "quoted KEY containg slash" );

$resultlist = $data ~~ dpath '//AAA/*/CCC[size == 3]'; # array with 3 elements
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ] ], 'FILTER size == 3' );

$resultlist = $data ~~ dpath '//AAA/*/CCC[size == 1]'; # array with 1 elements
cmp_bag($resultlist, [ 'affe' ], 'FILTER size == 1' );

$resultlist = $data ~~ dpath '//AAA/*/CCC[size >= 1]'; # array with >= elements
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'], [ 'RR1', 'RR2', 'RR3' ], 'affe' ], 'FILTER size >= 1' );

$resultlist = $data ~~ dpath '/AAA[size == 3]'; # hash with >= elements
cmp_bag($resultlist, [
                      {
                       BBB => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                       RRR => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                       DDD => { EEE  => [ qw/ uuu vvv www / ] },
                      }
                     ], 'FILTER hash size == 3' );

$resultlist = $data ~~ dpath '/AAA[size != 3]'; # hash with keys
cmp_bag($resultlist, [ ], 'FILTER hash size != 3' );

$resultlist = $data ~~ dpath '//AAA[size >= 1]'; # hash with >= elements
cmp_bag($resultlist, [
                      {
                       BBB => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                       RRR => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                       DDD => { EEE  => [ qw/ uuu vvv www / ] },
                      },
                      { BBB => { CCC => 'affe' } },
                     ], 'FILTER hash size >= 1' );

$resultlist = $data ~~ dpath '//AAA[ size >= 3 ]'; # hash with >= 3 elements
cmp_bag($resultlist, [
                      {
                       BBB => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                       RRR => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                       DDD => { EEE  => [ qw/ uuu vvv www / ] },
                      },
                     ], 'FILTER hash size >= 3' );

$resultlist = $data ~~ dpath '//AAA[size == 1]'; # hash with >= elements
cmp_bag($resultlist, [
                      { BBB => { CCC => 'affe' } },
                     ], 'ANYWHERE + FILTER hash size == 1' );

$resultlist = $data ~~ dpath '//AAA/*/CCC/*';
cmp_bag($resultlist, [ 'affe', 'XXX', 'YYY', 'ZZZ', 'RR1', 'RR2', 'RR3' ] );

TODO: {

        local $TODO = 'far away future spec';

        $resultlist = $data ~~ dpath '/AAA/*/CCC/* | /some/where/else/AAA/BBB/CCC';
        # ( 'XXX', 'YYY', 'ZZZ', 'affe' )
        cmp_bag($resultlist, [ 'XXX', 'YYY', 'ZZZ', 'RR1', 'RR2', 'RR3', 'affe' ] );

}

$resultlist = $data ~~ dpath '/AAA/*/CCC/*[0]';
cmp_bag($resultlist, [ 'XXX', 'RR1' ], "ANYSTEP + FILTER int 0" );
$resultlist = $data ~~ dpath '/AAA/*/CCC/*[ 0 ]';
cmp_bag($resultlist, [ 'XXX', 'RR1' ], "ANYSTEP + FILTER int 0 whitespace" );

$resultlist = $data ~~ dpath '/AAA/*/CCC/*[2]';
cmp_bag($resultlist, [ 'ZZZ', 'RR3' ], "ANYSTEP + FILTER int 2" );
$resultlist = $data ~~ dpath '/AAA/*/CCC/*[ 2 ]';
cmp_bag($resultlist, [ 'ZZZ', 'RR3' ], "ANYSTEP + FILTER int 2 whitespace" );

$resultlist = $data ~~ dpath '/AAA/*/CCC/*[-1]';
cmp_bag($resultlist, [ 'ZZZ', 'RR3' ], "ANYSTEP + FILTER int -1" );
$resultlist = $data ~~ dpath '/AAA/*/CCC/*[ -1 ]';
cmp_bag($resultlist, [ 'ZZZ', 'RR3' ], "ANYSTEP + FILTER int -1 whitespace" );

$resultlist = $data ~~ dpath '//AAA/*/CCC/*[0]';
cmp_bag($resultlist, [ 'XXX', 'RR1', 'affe' ], "ANYWHERE + ANYSTEP + FILTER int 0" );
$resultlist = $data ~~ dpath '//AAA/*/CCC/*[ 0 ]';
cmp_bag($resultlist, [ 'XXX', 'RR1', 'affe' ], "ANYWHERE + ANYSTEP + FILTER int 0 whitespace" );

$resultlist = $data ~~ dpath '//AAA/*/CCC/*[-3]';
cmp_bag($resultlist, [ 'XXX', 'RR1', ], "ANYWHERE + ANYSTEP + FILTER int -3" );
$resultlist = $data ~~ dpath '//AAA/*/CCC/*[ -3 ]';
cmp_bag($resultlist, [ 'XXX', 'RR1', ], "ANYWHERE + ANYSTEP + FILTER int -3 whitespace" );

$resultlist = $data ~~ dpath '//AAA/*/CCC/*[2]';
cmp_bag($resultlist, [ 'ZZZ', 'RR3' ], "ANYWHERE + ANYSTEP + FILTER int 2" );
$resultlist = $data ~~ dpath '//AAA/*/CCC/*[ 2 ]';
cmp_bag($resultlist, [ 'ZZZ', 'RR3' ], "ANYWHERE + ANYSTEP + FILTER int 2 whitespace" );

$resultlist = $data ~~ dpath '/AAA/*/CCC[2]';
cmp_bag($resultlist, [ ], "KEY + FILTER int" );

$resultlist = $data ~~ dpath '//AAA/*/CCC[2]';
cmp_bag($resultlist, [ ], "ANYWHERE + KEY + FILTER int" );


$resultlist = $data ~~ dpath '/AAA/*/CCC[0]';
#diag Dumper($resultlist);
cmp_bag($resultlist, [ [ 'XXX', 'YYY', 'ZZZ' ], [ 'RR1', 'RR2', 'RR3' ] ], "KEY + FILTER int 0" );

$resultlist = $data ~~ dpath '/AAA/*/CCC[1]';
cmp_bag($resultlist, [ ], "KEY + FILTER int 1" );

$resultlist = $data ~~ dpath '//AAA/*/CCC[0]';
#diag Dumper($resultlist);
cmp_bag($resultlist, [ [ 'XXX', 'YYY', 'ZZZ' ], [ 'RR1', 'RR2', 'RR3' ], 'affe' ], "ANYWHERE + KEY + FILTER int 0" );

$resultlist = $data ~~ dpath '//AAA/*/CCC[1]';
#diag Dumper($resultlist);
cmp_bag($resultlist, [ ], "ANYWHERE + KEY + FILTER int 1" );

# ----------------------------------------

my $data2 = [
             'UUU',
             'VVV',
             'WWW',
             {
              AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] } } },
            ];

$resultlist = $data2 ~~ dpath '/*'; # /*
cmp_bag($resultlist, [ 'UUU', 'VVV', 'WWW', { AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] } } } ], "ROOT + ANYSTEP" );

$resultlist = $data2 ~~ dpath '/';
cmp_bag($resultlist, [ $data2 ], "ROOT" );

$resultlist = $data2 ~~ dpath '//';
cmp_bag($resultlist, [
                      qw( UUU VVV WWW XXX YYY ZZZ ),
                      [ qw/ XXX YYY ZZZ / ],
                      { CCC => [ qw/ XXX YYY ZZZ / ] },
                      { BBB => { CCC => [ qw/ XXX YYY ZZZ / ] } },
                      { AAA => { BBB => { CCC => [ qw/ XXX YYY ZZZ / ] } } },
                      $data2,
                     ], "ANYWHERE" );

$resultlist = $data2 ~~ dpath '//*[ size == 3 ]';
cmp_bag($resultlist, [ [ qw/ XXX YYY ZZZ / ] ], "ANYWHERE + ANYSTEP + FILTER int" );

$resultlist = $data2 ~~ dpath '/*[2]';
cmp_bag($resultlist, [ 'WWW' ], "ROOT + ANYSTEP + FILTER int: plain value" );

$resultlist = $data2 ~~ dpath '/*[3]';
# ( { AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] } } } )
cmp_bag($resultlist, [ { AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] } } } ], "ROOT + ANYSTEP + FILTER int: ref value" );

$resultlist = $data2 ~~ dpath '//*[2]';
cmp_bag($resultlist, [ 'WWW', 'ZZZ' ], "ANYWHERE + ANYSTEP + FILTER int" );

# basic eval filters
$resultlist = $data2 ~~ dpath '/*/AAA/BBB/CCC';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'] ], "FILTER eval prepare" );
$resultlist = $data2 ~~ dpath '/*/AAA/BBB/CCC[17 == 17]';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'] ], "FILTER eval simple true" );
$resultlist = $data2 ~~ dpath '/*/AAA/BBB/CCC[0 == 0]';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'] ], "FILTER eval simple true with false values" );
$resultlist = $data2 ~~ dpath '/*/AAA/BBB/CCC["foo" eq "foo"]';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'] ], "FILTER eval simple true with strings" );
$resultlist = $data2 ~~ dpath '/*/AAA/BBB/CCC[1 == 2]';
cmp_bag($resultlist, [ ], "FILTER eval simple false" );
$resultlist = $data2 ~~ dpath '/*/AAA/BBB/CCC["foo" eq "bar"]';
cmp_bag($resultlist, [ ], "FILTER eval simple false with strings" );

# ----------------------------------------

my $data3  = {
              AAA  => bless( { BBB => { CCC  => [ qw/ XXX YYY ZZZ / ] } }, "Foo::Bar"), # blessed BBB
              some => { where => { else => {
                                            AAA => { BBB => { CCC => 'affe' } }, # plain BBB
                                           } } },
              neighbourhoods => [
                                 { 'DDD' => { EEE => bless( { F1 => 'affe',
                                                       F2 => 'tiger',
                                                       F3 => 'fink',
                                                       F4 => 'star',
                                                     }, "Affe"),
                                              FFF => 'interesting value' }
                                 },
                                 { 'DDD' => { EEE => { F1 => 'bla',
                                                       F2 => 'bli',
                                                       F3 => 'blu',
                                                       F4 => 'blo',
                                                     },
                                              FFF => 'boring value' }
                                 },
                                 { 'DDD' => { EEE => { F1 => 'xbla',
                                                       F2 => 'xbli',
                                                       F3 => 'xblu',
                                                       F4 => 'xblo',
                                                     },
                                              FFF => 'third value' }
                                 },
                                 { 'DDD' => { EEE => { F1 => 'ybla',
                                                       F2 => 'ybli',
                                                       F3 => 'yblu',
                                                       F4 => 'yblo',
                                                     },
                                              FFF => 'fourth value' }
                                 },
                                ],
             };

# ------------------------------

$resultlist = $data3 ~~ dpath '//AAA/BBB/CCC';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'], 'affe' ], "ANYWHERE + KEYs in blessed structs" );

$resultlist = $data3 ~~ dpath '//AAA//BBB/CCC';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'], 'affe' ], "ANYWHERE + ANYWHERE + KEYs in blessed structs" );

$resultlist = $data3 ~~ dpath '//AAA//BBB//CCC';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'], 'affe' ], "ANYWHERE + ANYWHERE + ANYWHERE + KEYs in blessed structs" );

SKIP: {
        skip "Filter functions with optional args are deprecated, use the is_XXX(args) form instead.", 1;
        $resultlist = $data3 ~~ dpath '//AAA[ reftype("HASH") ]/BBB/CCC';
        cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'], 'affe' ], "ANYWHERE + FILTER reftype funcall + KEYs" );
}

$resultlist = $data3 ~~ dpath '//AAA[ is_reftype("HASH") ]/BBB/CCC';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'], 'affe' ], "ANYWHERE + FILTER reftype funcall + KEYs" );

$resultlist = $data3 ~~ dpath '//AAA[ reftype eq "HASH" ]/BBB/CCC';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'], 'affe' ], "ANYWHERE + FILTER reftype eq + KEYs" );

$resultlist = $data3 ~~ dpath '//AAA[ reftype ~~ /ASH/ ]/BBB/CCC';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'], 'affe' ], "ANYWHERE + FILTER reftype smartmatch + KEYs" );

$resultlist = $data3 ~~ dpath '//AAA[ isa("Foo::Bar") ]/BBB/CCC';
cmp_bag($resultlist, [ ['XXX', 'YYY', 'ZZZ'] ], "ANYWHERE + FILTER isa + KEYs" );

$resultlist = $data3 ~~ dpath '//DDD/EEE/F1[ value eq "affe" ]/../../FFF'; # the DDD/FFF where the neighbor DDD/EEE/F1 == "affe"
cmp_bag($resultlist, [ 'interesting value' ], "ANYWHERE + KEYs + FILTER in blessed structs" );

# ------------------------------

$resultlist = $data3 ~~ dpath '/neighbourhoods/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ROOT + KEYs + FILTER int 0 + KEYs" );

$resultlist = $data3 ~~ dpath '/*[key ~~ /neighbourhoods/]/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ROOT + ANYSTEP + FILTER eval key matches + FILTER int 0 + KEYs" );

$resultlist = $data3 ~~ dpath '/*/.[key ~~ /neighbourhoods/]/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ROOT + ANYSTEP + NOSTEP + FILTER eval key matches + FILTER int 0 + KEYs" );

$resultlist = $data3 ~~ dpath '/*/*/../.[key ~~ /neighbourhoods/]/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ROOT + ANYSTEP + PARENT + NOSTEP + FILTER eval key matches + FILTER int 0 + KEYs" );

$resultlist = $data3 ~~ dpath '/neighbourhoods/*[1]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'boring value' ], "ROOT + KEYs + FILTER int 1 + KEYs" );

$resultlist = $data3 ~~ dpath '//neighbourhoods/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ANYWHERE + KEYs + FILTER int 0 + KEYs" );

$resultlist = $data3 ~~ dpath '//neighbourhoods/*[1]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'boring value' ], "ANYWHERE + KEYs + FILTER int 1 + KEYs" );

$resultlist = $data3 ~~ dpath '//neighbourhoods/*[2]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'third value' ], "ANYWHERE + KEYs + FILTER int 2 + KEYs" );

$resultlist = $data3 ~~ dpath '//neighbourhoods/*[3]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'fourth value' ], "ANYWHERE + KEYs + FILTER int 3 + KEYs" );

$resultlist = $data3 ~~ dpath '//neighbourhoods/*[-1]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'fourth value' ], "ANYWHERE + KEYs + FILTER int -1 + KEYs" );

$resultlist = $data3 ~~ dpath '//neighbourhoods/*[-2]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'third value' ], "ANYWHERE + KEYs + FILTER int -2 + KEYs" );

$resultlist = $data3 ~~ dpath '//neighbourhoods/*[-3]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'boring value' ], "ANYWHERE + KEYs + FILTER int -3 + KEYs" );

$resultlist = $data3 ~~ dpath '//neighbourhoods/*[-4]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ANYWHERE + KEYs + FILTER int -4 + KEYs" );

$resultlist = $data3 ~~ dpath '//neighbourhoods/*[-5]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ ], "ANYWHERE + KEYs + FILTER too negative int + KEYs" );

$resultlist = $data3 ~~ dpath '//neighbourhoods/*[20]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ ], "ANYWHERE + KEYs + FILTER too high int + KEYs" );

$resultlist = $data3 ~~ dpath '/*[key eq "neighbourhoods"]/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ROOT + ANYSTEP + FILTER eval key eq + FILTER int" );

$resultlist = $data3 ~~ dpath '/*/.[key eq "neighbourhoods"]/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ROOT + ANYSTEP + NOSTEP + FILTER eval key eq + FILTER int" );

$resultlist = $data3 ~~ dpath '/*/*/../.[key eq "neighbourhoods"]/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ROOT + ANYSTEP + PARENT + NOSTEP + FILTER eval key eq + FILTER int" );

$resultlist = $data3 ~~ dpath '/*[key ~~ /neigh.*hoods/]/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ROOT + ANYSTEP + FILTER eval key matches + FILTER int" );

$resultlist = $data3 ~~ dpath '/*/.[key ~~ /neigh.*hoods/]/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ROOT + ANYSTEP + NOSTEP + FILTER eval key matches + FILTER int" );

$resultlist = $data3 ~~ dpath '/*/*/../.[key ~~ /neigh.*hoods/]/*[0]/DDD/FFF';
# ( 'interesting value' )
cmp_bag($resultlist, [ 'interesting value' ], "ROOT + ANYSTEP + PARENT + NOSTEP + FILTER eval key matches + FILTER int" );

# ----------------------------------------

my $data4  = {
              AAA  => { BBB => { CCC  => [ qw/
                                                     XXX
                                                     YYY
                                                     ZZZ
                                                     XXXX
                                                     YYYY
                                                     ZZZZ
                                             / ] } },
              some => { where => { else => {
                                            AAA => { BBB => { CCC => 'affe' } }, # plain BBB
                                           } } },
              neighbourhoods => [
                                 { 'DDD' => { EEE => { F1 => 'affe',
                                                       F2 => 'tiger',
                                                       F3 => 'fink',
                                                       F4 => 'star',
                                                     },
                                              FFF => 'interesting value' }
                                 },
                                 { 'DDD' => { EEE => { F1 => 'bla',
                                                       F2 => 'bli',
                                                       F3 => 'blu',
                                                       F4 => 'blo',
                                                     },
                                              FFF => 'boring value' }
                                 },
                                ],
             };

$resultlist = $data4 ~~ dpath '//AAA/BBB/CCC/*[ affe ]';
cmp_bag($resultlist, [ 'affe' ], "FILTER: affe" );

$resultlist = $data4 ~~ dpath '/AAA/BBB/CCC/*[ idx == 1 ]';
cmp_bag($resultlist, [ 'YYY' ], "FILTER: index" );

$resultlist = $data4 ~~ dpath '/AAA/BBB/CCC/*[ 1 ]';
cmp_bag($resultlist, [ 'YYY' ], "FILTER: index" );

$resultlist = $data4 ~~ dpath '//AAA/BBB/CCC/*[ /..../ ]';
cmp_bag($resultlist, [ 'XXXX', 'YYYY', 'ZZZZ', 'affe' ], "FILTER eval regex five chars" );

$resultlist = $data4 ~~ dpath '//AAA/BBB/CCC/*[ /[A-Z]+/ ]';
cmp_bag($resultlist, [ 'XXX', 'YYY', 'ZZZ', 'XXXX', 'YYYY', 'ZZZZ', ], "FILTER eval regex just capitalizes" );

SKIP:
{
        skip "quote semantics changed", 1;
        $resultlist = $data4 ~~ dpath '//AAA/BBB/CCC/"*"[ m/[A-Z]+/ ]';
        cmp_bag($resultlist, [ 'XXX', 'YYY', 'ZZZ', 'XXXX', 'YYYY', 'ZZZZ', ], "FILTER eval regex with quotes and slashes" );
}

$resultlist = $data ~~ dpath '//AAA/BBB/*[key eq "CCC"]';
cmp_bag($resultlist, [
                      [ qw/ XXX YYY ZZZ / ],
                      'affe',
                     ], "ANYWHERE + STEP + ANYSTEP + FILTER eval key eq string" );

$resultlist = $data ~~ dpath '//AAA/BBB/.[key eq "CCC"]';
cmp_bag($resultlist, [ ], "ANYWHERE + STEP + NOSTEP + FILTER eval key eq string" );

$resultlist = $data ~~ dpath '//AAA/*[ key eq "CCC" ]';
cmp_bag($resultlist, [
                     ], "ANYWHERE + ANYSTEP + FILTER eval key eq string" );

$resultlist = $data ~~ dpath '//AAA/*/*[ key eq "CCC" ]';
cmp_bag($resultlist, [
                      [ qw/ XXX YYY ZZZ / ],
                      [ qw/ RR1 RR2 RR3 / ],
                      'affe',
                     ], "ANYWHERE + ANYSTEP + ANYSTEP + FILTER eval key eq string" );

$resultlist = $data ~~ dpath '//AAA/*/CCC';
cmp_bag($resultlist, [
                      [ qw/ XXX YYY ZZZ / ],
                      [ qw/ RR1 RR2 RR3 / ],
                      'affe',
                     ], "ANYWHERE + STEP + ANYSTEP + STEP" );

$resultlist = $data ~~ dpath '//AAA/*/CCC/.[ key eq "CCC" ]';
cmp_bag($resultlist, [
                      [ qw/ XXX YYY ZZZ / ],
                      [ qw/ RR1 RR2 RR3 / ],
                      'affe',
                     ], "ANYWHERE + STEP + ANYSTEP + STEP + FILTER eval key eq last STEP" );

$resultlist = $data ~~ dpath '//.[ key eq "DD DD" ]';
cmp_bag($resultlist, [
                      { 'EE/E' => { CCC => 'zomtec' } }
                     ], "ANYWHERE + NOSTEP + FILTER eval key" );

$resultlist = $data ~~ dpath '//.[ key eq "EE/E" ]';
cmp_bag($resultlist, [
                      { CCC => 'zomtec' }
                     ], "ANYWHERE + NOSTEP + FILTER eval key + slash in eval" );

$resultlist = $data ~~ dpath '//AAA/*/CCC/.[ key eq "CCC" ]';
cmp_bag($resultlist, [
                      [ qw/ XXX YYY ZZZ / ],
                      [ qw/ RR1 RR2 RR3 / ],
                      'affe',
                     ], "ANYWHERE + STEP + ANYSTEP + STEP + FILTER eval key eq last STEP" );

$resultlist = $data ~~ dpath '//AAA/*[ key ~~ /.../ ]';
cmp_bag($resultlist, [
                      { CCC  => [ qw/ XXX YYY ZZZ / ] },
                      { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                      { EEE  => [ qw/ uuu vvv www / ] },
                      { CCC => 'affe' },
                     ], "ANYWHERE + STEP + ANYSTEP + FILTER eval key matches" );

$resultlist = $data ~~ dpath '//AAA/*[ key ~~ qr(...) ]';
cmp_bag($resultlist, [
                      { CCC  => [ qw/ XXX YYY ZZZ / ] },
                      { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                      { EEE  => [ qw/ uuu vvv www / ] },
                      { CCC  => 'affe' },
                     ], "ROOT + ANYSTEP + FILTER eval key matches qr()" );

$resultlist = $data ~~ dpath '//AAA/*[ key ~~ m(...) ]';
cmp_bag($resultlist, [
                      { CCC  => [ qw/ XXX YYY ZZZ / ] },
                      { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                      { EEE  => [ qw/ uuu vvv www / ] },
                      { CCC  => 'affe' },
                     ], "ROOT + ANYSTEP + FILTER eval with key matches m(...)" );

$resultlist = $data ~~ dpath '//AAA/*[ key ~~ /CC/ ]';
cmp_bag($resultlist, [ ], "ROOT + ANYSTEP + FILTER eval with key matches /CC/" );

$resultlist = $data ~~ dpath '//AAA/*/*[ key ~~ /CC/ ]';
cmp_bag($resultlist, [
                      [ qw/ XXX YYY ZZZ / ],
                      [ qw/ RR1 RR2 RR3 / ],
                      'affe',
                     ], "ROOT + ANYSTEP + ANYSTEP + FILTER eval with key matches /CC/" );

$resultlist = $data ~~ dpath('//CCC/*[value eq "RR2"]');
#print STDERR "resultlist = ", Dumper($resultlist);
cmp_bag($resultlist, [ 'RR2' ], "ANYWHERE + ANYSTEP + FILTER eval value" );

# print STDERR "**************************************************\n";
# print STDERR "resultlist = ", Dumper($data ~~ dpath('//CCC/*[value eq "RR2"]')); # /..
$resultlist = $data ~~ dpath('//CCC/*[value eq "RR2"]/..');
#print STDERR "resultlist = ", Dumper($resultlist);
cmp_bag($resultlist, [ [ 'RR1', 'RR2', 'RR3' ] ], "ANYWHERE + ANYSTEP + FILTER eval value + PARENT" );
# print STDERR "**************************************************\n";

$resultlist = $data ~~ dpath('//CCC/*[value eq "RR2"]/../..');
#print STDERR "resultlist = ", Dumper($resultlist);
cmp_bag($resultlist, [ { CCC  => [ 'RR1', 'RR2', 'RR3' ] } ], "ANYWHERE + ANYSTEP + FILTER eval value + 2xPARENT" );

# ----------------------------------------


my $data5 = {
             AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                       RRR   => { CCC  => [ qw/ RR1 RR2 RR3 / ] },
                       DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                       "*"   => { CCC  => [ qw/ ASTAR BSTAR CSTAR / ] },
                       "//"  => { CCC  => [ qw/ ASLASH BSLASH CSLASH / ] },
                       ".."  => { CCC  => [ qw/ ADOTDOT BDOTDOT CDOTDOT / ] },
                       "."   => { CCC  => [ qw/ ADOT BDOT CDOT / ] },
                     },
            };

$resultlist = $data5 ~~ dpath('/AAA/*/CCC');
cmp_bag($resultlist, [ [ qw/ XXX YYY ZZZ / ],
                       [ qw/ RR1 RR2 RR3 / ],
                       [ qw/ ASTAR BSTAR CSTAR / ],
                       [ qw/ ASLASH BSLASH CSLASH / ],
                       [ qw/ ADOTDOT BDOTDOT CDOTDOT / ],
                       [ qw/ ADOT BDOT CDOT / ],
                     ], "KEYs + ANYSTEP again" );

$resultlist = $data5 ~~ dpath('/AAA/"*"/CCC');
cmp_bag($resultlist, [ [ qw/ ASTAR BSTAR CSTAR / ] ], "KEYs + (*)" );

$resultlist = $data5 ~~ dpath('/AAA/"//"/CCC');
cmp_bag($resultlist, [ [ qw/ ASLASH BSLASH CSLASH / ] ], "KEYs + (//)" );

$resultlist = $data5 ~~ dpath('/AAA/".."/CCC');
cmp_bag($resultlist, [ [ qw/ ADOTDOT BDOTDOT CDOTDOT / ] ], "KEYs + (..)" );

$resultlist = $data5 ~~ dpath('/AAA/"."/CCC');
cmp_bag($resultlist, [ [ qw/ ADOT BDOT CDOT / ] ], "KEYs + (.)" );

# ----------------------------------------


my $data6 = bless [
                   [ 2, 3, 5, 7, 11, 13, 17, 19, 23 ],
                   [ 1, 2, 3, 4 ],
                   [ qw( AAA BBB CCC DDD ) ],
                   [ 11, 22, 33 ],
                   {
                    hot => {
                            stuff => {
                                      ahead => [ qw( affe tiger fink star ) ],
                                      ""    => "some value on empty key",
                                     }
                           }
                   },
                  ], "Some::Funky::Stuff";

$resultlist = $data6 ~~ dpath '/.[ isa("Foo::Bar") ]';
cmp_bag($resultlist, [ ], "ROOT + NOSTEP + FILTER isa (with no match)" );

$resultlist = $data6 ~~ dpath '/.[ isa("Some::Funky::Stuff") ]';
cmp_bag($resultlist, [ $data6 ], "ROOT + NOSTEP + FILTER isa" );

# chaining filters by using NOSTEP

$resultlist = $data6 ~~ dpath '/.[ isa("Some::Funky::Stuff") ]/.[ size == 5 ]';
cmp_bag($resultlist, [ $data6 ], "ROOT + NOSTEP + FILTER isa + FILTER size" );

$resultlist = $data6 ~~ dpath '/.[ isa("Some::Funky::Stuff") ]/.[ size == 5 ]/.[ reftype eq "ARRAY" ]';
cmp_bag($resultlist, [ $data6 ], "ROOT + NOSTEP + FILTER isa + FILTER size + FILTER reftype" );

$resultlist = $data6 ~~ dpath '//.[ size == 4 ]';
cmp_bag($resultlist, [
                      [ 1, 2, 3, 4 ],
                      [ qw( AAA BBB CCC DDD ) ],
                      [ qw( affe tiger fink star ) ],
                     ], "ANYWHERE + NOSTEP + FILTER int" );

$resultlist = $data6 ~~ dpath '//""/';
cmp_bag($resultlist, [ "some value on empty key" ], "empty key");

my $data7 =  [
              [ 2, 3, 5, 7, 11, 13, 17, 19, 23 ],
              [ 1, 2, 3, 4 ],
              [ qw( AAA BBB CCC DDD ) ],
              [ 11, 22, 33 ],
              {
               hot => {
                       stuff => {
                                 ahead => [ qw( affe tiger fink star ) ],
                                 ""    => "some value on empty key",
                                }
                      }
              },
             ];

$resultlist = $data7 ~~ dpathr '//.[ size == 4 ]';

cmp_bag($resultlist, [
                      \($data7->[1]),
                      \($data7->[2]),
                      \($data7->[4]{hot}{stuff}{ahead}),
                     ], "ANYWHERE + NOSTEP + FILTER int (REFERENCES)" );

${$resultlist->[0]} = [ qw(one two three four) ];
${$resultlist->[1]} = "there once was an array in LA";
${$resultlist->[2]} = { affe => "tiger",
                        fink => "star",
                      };

my $data7_expected_change = [
                             [ 2, 3, 5, 7, 11, 13, 17, 19, 23 ],
                             [ 'one', 'two', 'three', 'four' ],
                             "there once was an array in LA",
                             [ 11, 22, 33 ],
                             {
                              hot => {
                                      stuff => {
                                                ahead => { affe => "tiger",
                                                           fink => "star" },
                                                ""    => "some value on empty key",
                                               }
                                     }
                             },
                            ];

# diag Dumper($resultlist);
# diag Dumper($data7_expected_change);
# diag Dumper($data7);

cmp_bag($data7, $data7_expected_change, "ANYWHERE + NOSTEP + FILTER int (REFERENCES CHANGED)" );

my $data8 = {
             AAA  => { BBB   => { CCC  => [ qw/ XXX YYY ZZZ / ] },
                       RRR   => { CCC  => bless([
                                                 [ qw/ RR1 RR2 RR3 /],
                                                 [ 11, 22, 33 ],
                                                ], "Zomtec") },
                       DDD   => { EEE  => [ qw/ uuu vvv www / ] },
                     },
             some => { where => { else => {
                                           AAA => { BBB => { CCC => 'affe' } },
                                          } } },
             strange_keys => { 'DD DD' => { 'EE/E' => { CCC => 'zomtec' } } },
            };


TODO: {
        local $TODO = "REAL TODO FIX ME SOON!";

        $resultlist = $data8 ~~ dpath('//CCC//*[ value eq "RR3" ]/..'); # /../*[1]');
        # print STDERR "resultlist = ", Dumper($resultlist);
        cmp_bag($resultlist, [ [ 11, 22, 33 ] ], "ANYWHERE + ANYSTEP + FILTER eval value + PARENT + bless" );

}

TODO: {
        local $TODO = "REAL TODO FIX ME SOON! (but depends on test before)";

        $resultlist = $data8 ~~ dpath('//CCC//*[ value eq "RR3" ]/../../*[1]');
        # print STDERR "resultlist = ", Dumper($resultlist);
        cmp_bag($resultlist, [ [ 11, 22, 33 ] ], "ANYWHERE + ANYSTEP + FILTER eval value + 2xPARENT + FILTER int + bless" );
}

done_testing();
