#search all modules as file paths
use strict;
use warnings;
use File::Find;
use Path::Tiny;
use Test::More;

my @modules;
sub wanted {
    $File::Find::name =~ m#SLUB/LZA/.+\.pm$# && -f $_ && push @modules, $File::Find::name;
}
find(\&wanted, "lib/");

# allowed:    exists $foo->{$bar}
# allowed:    exists $foo->{$bar} and exists $foo->{$bar}->{$baz}
# forbidden:  exists $foo->{$bar}->{$baz}
#my $rx_exists=qr{(?!(&&|and) *)(?<=exists)};
#my $rx_hash_or_hashref=qr/(\$[a-z_]+)((->)?{[^}]*})((->)?{[^}]*})/;
#my $regex_match=qr/$rx_exists $rx_hash_or_hashref/;
use diagnostics;
foreach my $module (@modules) {
    my @lines = path($module)->lines;
    my $errors = 0;
    for (my $i=0; $i<=$#lines; $i++) {
        next unless $lines[$i]=~m/exists/;
        my $reversed_line = reverse scalar $lines[$i];
        # aus  "exists $foo->{bar}->{baz}"
        # wird "}zab{>-}rab{>-oof$ stsixe"
        # aus  "exists $foo->{bar} and exists $foo->{bar}->{baz}"
        # wird "}zab{>-}rab{>-oof$ stsixe dna }rab{>-oof$ stsixe"
        # damit haben wir mit Trenner ' dna ' folgende Teilstrings:
        # "}zab{>-}rab{>-oof$ stsixe" und
        #        "}rab{>-oof$ stsixe"
        # Damit können wir nach Teilstrings suchen
        # my $ref = qr/\}[^{]*{/;
        # m/($ref>-)($ref>-){1,}[a-z]*\$/ würde auf den Hashref matchen, in $1 hätten wir Treffer für n-ten Hashref-teil, in $2 Treffer für Rest
        # was wir fordern, ist, dass lookahead der Rest mit ' dna ' verbunden ist:
        # m/($ref>-)($ref>-){1,}([a-z]*\$)(?= dna $2$3)/g
        my $rx_ref = qr/\}[^{]*{/;
        no warnings;
        if ($reversed_line=~m/($rx_ref(?:>-)?)($rx_ref(?:>-)?){1,}([a-z]*\$ stsixe)(?! dna $2$3)/g) {
            use warnings;
            #print "line=$lines[$i]\n";
            my $lineno = $i + 1;
            $errors++;
            my $match1 = reverse scalar $1;
            my $match2 = reverse scalar $2;
            my $match3 = reverse scalar $3;
            fail("module $module uses 'exists' on nested hash or hashrefs, but this is dangerous,
             because values will be generated, see 'perldoc -f exists' for details.
             Here the problematic code:
             ---------- snip ---------
             $match3$match2$match1
             ---------- snap ---------
              (line $lineno)
             better use pattern like this:
             ---------- snip ---------
             $match3$match2 and $match3$match2$match1
             ---------- snap ---------

");

        }
    }
    if ($errors == 0) {
        pass("module $module");
    }
}

done_testing();
1;
