# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.


##################
#Bugzilla Test 11#
##POD validation##

use 5.14.0;
use strict;
use warnings;

use lib qw(. lib local/lib/perl5 t);

use Support::Files;
use Pod::Checker;
use Pod::Coverage;

use Test::More tests => scalar(@Support::Files::testitems)
  + scalar(@Support::Files::module_files);

# These methods do not need to be documented by default.
use constant DEFAULT_WHITELIST =>
  qr/^(?:new|new_from_list|check|run_create_validators|[A-Z_]+)$/;

# These subroutines do not need to be documented, generally because
# you shouldn't call them yourself. No need to include subroutines
# of the form _foo(); they are already treated as private.
use constant SUB_WHITELIST => (
  'Bugzilla::Flag'     => qr/^(?:(force_)?retarget|force_cleanup)$/,
  'Bugzilla::FlagType' => qr/^sqlify_criteria$/,
  'Bugzilla::JobQueue' => qr/(?:^work_once|work_until_done|subprocess_worker)$/,
  'Bugzilla::Search'   => qr/^SPECIAL_PARSING$/,
  'Bugzilla::Template' => qr/^field_name$/,
  'Bugzilla::MIME'     => qr/^as_string$/,
);

# These modules do not need to be documented, generally because they
# are subclasses of another module which already has all the relevant
# documentation. Partial names are allowed.
use constant MODULE_WHITELIST => qw(
  Bugzilla::Auth::Login::
  Bugzilla::Auth::Persist::
  Bugzilla::Auth::Verify::
  Bugzilla::BugUrl::
  Bugzilla::Config::
  Bugzilla::Extension::
  Bugzilla::Job::
  Bugzilla::Migrate::
  docs::lib::Pod::Simple::
);

# Capture the TESTOUT from Test::More or Test::Builder for printing errors.
# This will handle verbosity for us automatically.
my $fh;
{
  no warnings qw(unopened);    # Don't complain about non-existent filehandles
  if (-e \*Test::More::TESTOUT) {
    $fh = \*Test::More::TESTOUT;
  }
  elsif (-e \*Test::Builder::TESTOUT) {
    $fh = \*Test::Builder::TESTOUT;
  }
  else {
    $fh = \*STDOUT;
  }
}

my @testitems = @Support::Files::testitems;

foreach my $file (@testitems) {
  $file =~ s/\s.*$//;    # nuke everything after the first space (#comment)
  next if (!$file);      # skip null entries
  my $error_count = podchecker($file, $fh);
  if ($error_count < 0) {
    ok(1, "$file does not contain any POD");
  }
  elsif ($error_count == 0) {
    ok(1, "$file has correct POD syntax");
  }
  else {
    ok(0, "$file has incorrect POD syntax --ERROR");
  }
}

my %sub_whitelist = SUB_WHITELIST;
my @module_files  = sort @Support::Files::module_files;

foreach my $file (@module_files) {
  my $module = $file;
  $module =~ s/\.pm$//;
  $module =~ s#/#::#g;
  $module =~ s/^extensions/Bugzilla::Extension/;

  my @whitelist = (DEFAULT_WHITELIST);
  push(@whitelist, $sub_whitelist{$module}) if $sub_whitelist{$module};

  # XXX Once all methods are correctly documented, nonwhitespace should
  # be set to 1.
  my $cover = Pod::Coverage->new(
    package       => $module,
    nonwhitespace => 0,
    trustme       => \@whitelist
  );
  my $coverage = $cover->coverage;
  my $reason   = $cover->why_unrated;

  if (defined $coverage) {
    if ($coverage == 1) {
      ok(1, "$file has POD for all methods");
    }
    else {
      ok(0,
            "$file POD coverage is "
          . sprintf("%u%%", 100 * $coverage)
          . ". Undocumented methods: "
          . join(', ', $cover->uncovered));
    }
  }

  # These errors are thrown when the module couldn't be loaded due to
  # a missing dependency.
  elsif ($reason =~ /^(?:no public symbols defined|requiring '[^']+' failed)$/) {
    ok(1, "$file cannot be loaded");
  }
  elsif ($reason eq "couldn't find pod") {
    if (grep { $module =~ /^\Q$_\E/ } MODULE_WHITELIST) {
      ok(1, "$file does not contain any POD (whitelisted)");
    }
    else {
      ok(0, "$file POD coverage is 0%");
    }
  }
  else {
    ok(0, "$file: $reason");
  }
}

exit 0;
