The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

use strict;
use warnings;

use Test::More tests => 546;

use lib qw(t t/data/static);
use Utils;


##############################################################
# Tests compilation of Module::ScanDeps
##############################################################
BEGIN { use_ok( 'Module::ScanDeps' ); }


##############################################################
# RECURSE OPTION TESTS

##############################################################
# Using the following dependency tree
#
#                            M
#                           /|\
#                          / | \
#                         /  |  \
#                        /   M   \
#                       /   / \   \
#                      /   /   \   \
#                     M   M     M   M
#                      \   \   /   /
#                       \   \ /   /
#                        \   M   /
#                         \  |  /
#                          \ | /
#                            M
#
#   With dependencies always going from the top downwards
##############################################################
my @roots1 = qw(t/data/static/outer_diamond_N.pm);
my $expected_rv1 =
{
  "inner_diamond_N.pm" => {
                            file    => generic_abs_path("t/data/static/inner_diamond_N.pm"),
                            key     => "inner_diamond_N.pm",
                            type    => "module",
                            used_by => ["outer_diamond_N.pm"],
                          },
  "outer_diamond_E.pm" => {
                            file    => generic_abs_path("t/data/static/outer_diamond_E.pm"),
                            key     => "outer_diamond_E.pm",
                            type    => "module",
                            used_by => ["outer_diamond_N.pm"],
                          },
  "outer_diamond_N.pm" => {
                            file => generic_abs_path("t/data/static/outer_diamond_N.pm"),
                            key  => "outer_diamond_N.pm",
                            type => "module",
                            uses => ["inner_diamond_N.pm", "outer_diamond_E.pm", "outer_diamond_W.pm"],
                          },
  "outer_diamond_W.pm" => {
                            file    => generic_abs_path("t/data/static/outer_diamond_W.pm"),
                            key     => "outer_diamond_W.pm",
                            type    => "module",
                            used_by => ["outer_diamond_N.pm"],
                          },
};

my $rv1 = scan_deps(
            files   => \@roots1,
            recurse => 0,
          );

compare_scandeps_rvs($rv1, $expected_rv1, \@roots1);


##############################################################
# Using the following dependency tree
#
#     InputA.pl       InputB.pl   InputC.pl
#       /  \             \           /
#      /    \             \         /
#     /      \             \       /
# TestA.pm  TestB.pm   TestC.pm   /
#                            \   /
#                             \ /
#                          TestD.pm
#
##############################################################
my @roots2 = qw(t/data/static/InputA.pl
                t/data/static/InputB.pl
                t/data/static/InputC.pl);

my $expected_rv2 =
{
  "InputA.pl" => {
                   file => generic_abs_path("t/data/static/InputA.pl"),
                   key  => "InputA.pl",
                   type => "data",
                   uses => ["TestA.pm", "TestB.pm"],
                 },
  "InputB.pl" => {
                   file => generic_abs_path("t/data/static/InputB.pl"),
                   key  => "InputB.pl",
                   type => "data",
                   uses => ["TestC.pm"],
                 },
  "InputC.pl" => {
                   file => generic_abs_path("t/data/static/InputC.pl"),
                   key  => "InputC.pl",
                   type => "data",
                   uses => ["TestD.pm"],
                 },
  "TestA.pm"  => {
                   file    => generic_abs_path("t/data/static/TestA.pm"),
                   key     => "TestA.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },
  "TestB.pm"  => {
                   file    => generic_abs_path("t/data/static/TestB.pm"),
                   key     => "TestB.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },
  "TestC.pm"  => {
                   file    => generic_abs_path("t/data/static/TestC.pm"),
                   key     => "TestC.pm",
                   type    => "module",
                   used_by => ["InputB.pl"],
                 },
  "TestD.pm"  => {
                   file    => generic_abs_path("t/data/static/TestD.pm"),
                   key     => "TestD.pm",
                   type    => "module",
                   used_by => ["InputC.pl"], # No "TestC.pm" used_by entry
                 },
};

my $rv2 = scan_deps(
            files   => \@roots2,
            recurse => 0,
          );

compare_scandeps_rvs($rv2, $expected_rv2, \@roots2);


##############################################################
# SKIP OPTION TESTS

##############################################################
# Dependency tree for tests
#
#     InputA.pl       InputB.pl   InputC.pl
#       /  \             \           /
#      /    \             \         /
#     /      \             \       /
# TestA.pm  TestB.pm   TestC.pm   /
#                            \   /
#                             \ /
#                          TestD.pm
#
##############################################################
my @roots_ABC = qw(t/data/static/InputA.pl
                   t/data/static/InputB.pl
                   t/data/static/InputC.pl);

##############################################################
my $expected_rv_ABC_skip_TestA =
{
  "InputA.pl" => {
                   file => generic_abs_path("t/data/static/InputA.pl"),
                   key  => "InputA.pl",
                   type => "data",
                   uses => ["TestA.pm", "TestB.pm"],
                 },
  "InputB.pl" => {
                   file => generic_abs_path("t/data/static/InputB.pl"),
                   key  => "InputB.pl",
                   type => "data",
                   uses => ["TestC.pm"],
                 },
  "InputC.pl" => {
                   file => generic_abs_path("t/data/static/InputC.pl"),
                   key  => "InputC.pl",
                   type => "data",
                   uses => ["TestD.pm"],
                 },

# It's OK to have this despite TestA.pm being skipped since this entry only shows
# InputA.pl has been parsed and shown to depend on TestA.pm
  "TestA.pm"  => {
                   file    => generic_abs_path("t/data/static/TestA.pm"),
                   key     => "TestA.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },

  "TestB.pm"  => {
                   file    => generic_abs_path("t/data/static/TestB.pm"),
                   key     => "TestB.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },
  "TestC.pm"  => {
                   file    => generic_abs_path("t/data/static/TestC.pm"),
                   key     => "TestC.pm",
                   type    => "module",
                   used_by => ["InputB.pl"],
                   uses    => ["TestD.pm"],
                 },
  "TestD.pm"  => {
                   file    => generic_abs_path("t/data/static/TestD.pm"),
                   key     => "TestD.pm",
                   type    => "module",
                   used_by => ["InputC.pl", "TestC.pm"],
                 },
};

my $rv3 = scan_deps(
            files   => \@roots_ABC,
            skip    => { generic_abs_path("t/data/static/TestA.pm") => 1 },
            recurse => 1,
          );

compare_scandeps_rvs($rv3, $expected_rv_ABC_skip_TestA, \@roots_ABC);


##############################################################
my $expected_rv_ABC_skip_TestC =
{
  "InputA.pl" => {
                   file => generic_abs_path("t/data/static/InputA.pl"),
                   key  => "InputA.pl",
                   type => "data",
                   uses => ["TestA.pm", "TestB.pm"],

                 },
  "InputB.pl" => {
                   file => generic_abs_path("t/data/static/InputB.pl"),
                   key  => "InputB.pl",
                   type => "data",
                   uses => ["TestC.pm"],
                 },
  "InputC.pl" => {
                   file => generic_abs_path("t/data/static/InputC.pl"),
                   key  => "InputC.pl",
                   type => "data",
                   uses => ["TestD.pm"],
                 },
  "TestA.pm"  => {
                   file    => generic_abs_path("t/data/static/TestA.pm"),
                   key     => "TestA.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },
  "TestB.pm"  => {
                   file    => generic_abs_path("t/data/static/TestB.pm"),
                   key     => "TestB.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },

# It's OK to have this despite TestC.pm being skipped since this entry only shows
# InputB.pl has been parsed and shown to depend on TestC.pm
  "TestC.pm"  => {
                   file    => generic_abs_path("t/data/static/TestC.pm"),
                   key     => "TestC.pm",
                   type    => "module",
                   used_by => ["InputB.pl"],
                 },

  "TestD.pm"  => {
                   file    => generic_abs_path("t/data/static/TestD.pm"),
                   key     => "TestD.pm",
                   type    => "module",
                   used_by => ["InputC.pl"],  # No TestC used_by
                 },
};

my $rv4 = scan_deps(
            files   => \@roots_ABC,
            skip    => { generic_abs_path("t/data/static/TestC.pm") => 1 },
            recurse => 1,
          );

compare_scandeps_rvs($rv4, $expected_rv_ABC_skip_TestC, \@roots_ABC);


##############################################################
# Test multiple skip entries
my $expected_rv_ABC_skip_TestA_TestC =
{
  "InputA.pl" => {
                   file => generic_abs_path("t/data/static/InputA.pl"),
                   key  => "InputA.pl",
                   type => "data",
                   uses => ["TestA.pm", "TestB.pm"],
                 },
  "InputB.pl" => {
                   file => generic_abs_path("t/data/static/InputB.pl"),
                   key  => "InputB.pl",
                   type => "data",
                   uses => ["TestC.pm"],
                 },
  "InputC.pl" => {
                   file => generic_abs_path("t/data/static/InputC.pl"),
                   key  => "InputC.pl",
                   type => "data",
                   uses => ["TestD.pm"],
                 },

# It's OK to have this despite TestA.pm being skipped since this entry only shows
# InputA.pl has been parsed and shown to depend on TestA.pm
  "TestA.pm"  => {
                   file    => generic_abs_path("t/data/static/TestA.pm"),
                   key     => "TestA.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },

  "TestB.pm"  => {
                   file    => generic_abs_path("t/data/static/TestB.pm"),
                   key     => "TestB.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },

# It's OK to have this despite TestC.pm being skipped since this entry only shows
# InputB.pl has been parsed and shown to depend on TestC.pm
  "TestC.pm"  => {
                   file    => generic_abs_path("t/data/static/TestC.pm"),
                   key     => "TestC.pm",
                   type    => "module",
                   used_by => ["InputB.pl"],
                 },

  "TestD.pm"  => {
                   file    => generic_abs_path("t/data/static/TestD.pm"),
                   key     => "TestD.pm",
                   type    => "module",
                   used_by => ["InputC.pl"],  # No TestC used_by
                 },
};

my $rv5 = scan_deps(
            files   => \@roots_ABC,
            skip    => { 
                         generic_abs_path("t/data/static/TestA.pm") => 1,
                         generic_abs_path("t/data/static/TestC.pm") => 1,
                       },
            recurse => 1,
          );

compare_scandeps_rvs($rv5, $expected_rv_ABC_skip_TestA_TestC, \@roots_ABC);


##############################################################
my @roots_AB = qw(t/data/static/InputA.pl
                  t/data/static/InputB.pl);

my $expected_rv_AB_skip_TestC =
{
  "InputA.pl" => {
                   file => generic_abs_path("t/data/static/InputA.pl"),
                   key  => "InputA.pl",
                   type => "data",
                   uses => ["TestA.pm", "TestB.pm"],
                 },
  "InputB.pl" => {
                   file => generic_abs_path("t/data/static/InputB.pl"),
                   key  => "InputB.pl",
                   type => "data",
                   uses => ["TestC.pm"],
                 },
  "TestA.pm"  => {
                   file    => generic_abs_path("t/data/static/TestA.pm"),
                   key     => "TestA.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },
  "TestB.pm"  => {
                   file    => generic_abs_path("t/data/static/TestB.pm"),
                   key     => "TestB.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },

# It's OK to have this despite TestC.pm being skipped since this entry only shows
# InputB.pl has been parsed and shown to depend on TestC.pm
  "TestC.pm"  => {
                   file    => generic_abs_path("t/data/static/TestC.pm"),
                   key     => "TestC.pm",
                   type    => "module",
                   used_by => ["InputB.pl"],
                 },
#
# No TestD entry
#
};

my $rv6 = scan_deps(
            files   => \@roots_AB,
            skip    => { generic_abs_path("t/data/static/TestC.pm") => 1 },
            recurse => 1,
          );

compare_scandeps_rvs($rv6, $expected_rv_AB_skip_TestC, \@roots_AB);

##############################################################

my $expected_rv_AB_skip_TestD =
{
  "InputA.pl" => {
                   file => generic_abs_path("t/data/static/InputA.pl"),
                   key  => "InputA.pl",
                   type => "data",
                   uses => ["TestA.pm", "TestB.pm"],
                 },
  "InputB.pl" => {
                   file => generic_abs_path("t/data/static/InputB.pl"),
                   key  => "InputB.pl",
                   type => "data",
                   uses => ["TestC.pm"],
                 },
  "TestA.pm"  => {
                   file    => generic_abs_path("t/data/static/TestA.pm"),
                   key     => "TestA.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },
  "TestB.pm"  => {
                   file    => generic_abs_path("t/data/static/TestB.pm"),
                   key     => "TestB.pm",
                   type    => "module",
                   used_by => ["InputA.pl"],
                 },
  "TestC.pm"  => {
                   file    => generic_abs_path("t/data/static/TestC.pm"),
                   key     => "TestC.pm",
                   type    => "module",
                   used_by => ["InputB.pl"],
                 },
#
# No TestD entry
#
};

my $rv7 = scan_deps(
            files   => \@roots_AB,
            skip    => { "t/data/static/TestD.pm" => 1 },
            recurse => 1,
          );

#is_deeply($rv7, $expected_rv_AB_skip_TestD);
compare_scandeps_rvs($rv7, $expected_rv_AB_skip_TestD, \@roots_AB);

__END__