The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#! /usr/bin/perl -w
# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl test.pl'

######################### We start with some black magic to print on failure.

# Change 1..1 below to 1..last_test_to_print .
# (It may become useful if the test is moved to ./t subdirectory.)

BEGIN { $| = 1; print "1..20\n"; }
END {print "not ok 1\n" unless $loaded;}
use Class::AutoloadCAN;
use Carp;
$loaded = 1;
print "ok 1\n";

my $tests_done = 1;

# The following classes are used in later tests.  They are here so that
# the inheritance is set up before those tests.
{
  package NoAutoload;

  sub implemented { "foo" };

  sub CAN {
    sub {"bar"};
  }

  package Base1;
  Class::AutoloadCAN->import;

  # This CAN is always paid attention to.
  sub CAN {
    my ($base_class, $method, $self, @args) = @_;
    return sub {"Base1"} if $method =~ /base1/;
  }

  package Base2;

  # This CAN is only paid attention to after we call import.
  sub CAN {
    my ($base_class, $method, $self, @args) = @_;
    return sub {"Base2"} if $method =~ /base2/;
  }

  package Child;
  @ISA = qw(Base1 Base2);

  # This CAN is paid attention to through inheritance.
  sub CAN {
    my ($base_class, $method, $self, @args) = @_;
    return sub {"Child"} if $method =~ /child/;
  }

  package GrandChild;
  @ISA = 'Child';
  sub can {"overridden"}

  package GreatGrandChild;
  use Class::AutoloadCAN;
  @ISA = 'GrandChild';
}

true(NoAutoload->can("implemented"), "Raw subs work");
true(NoAutoload->implemented eq "foo", "Raw subs are called normally");
true(!NoAutoload->can("not_implemented"), "CAN ignored if not AUTOLOADED");
eval {NoAutoload->not_implemented};
true($@ =~ /object method/, "Missing methods are missing if not AUTOLOADED");
eval {NoAutoload::not_implemented()};
true($@ =~ /subroutine/, "Missing subroutines are missing if not AUTOLOADED");
true(!NoAutoload->can("Child::implemented"), "Reset method search");
true(Child->can("child_method"), "CAN used in class");
true(Child->child_method eq "Child", "Child gets its own methods");
true(Child->can("base1_method"), "Inherited CAN seen");
true(Child->base1_method eq "Base1", "Child gets inherited CAN methods");
true(!Child->can("base2_method"), "CAN from ignored class, ignored");
eval "Child->base2_method";
true(($@ and $@ =~ /object method/), "Ignored class doesn't provide methods");
true(($@ and $@ =~ /"Child"/), "The error message includes the package");
true(($@ and $@ !~ /forgot to load/), "No load message on loaded package");
true(($@ =~ /eval/) ? 1 : 0, "The error comes from the right caller");
Class::AutoloadCAN->import("Base2");
true(Child->can("base2_method"), "Can unignore class");
true(Child->base2_method eq "Base2", "Unignored class provides methods");
true(GreatGrandChild->child_method eq "Child",
  "Can inherit through overridden can");
true(GreatGrandChild->can("child_method") eq "overridden",
  "But can is overridden");

sub true {
  my ($value, $test) = @_;
  confess("Wrong number of arguments") unless 2 == @_;
  $tests_done++;
  if ($value) {
    print "ok $tests_done\n";
    #print STDERR "\n\n$tests_done: $test succeeded\n";
  }
  else {
    print "not ok $tests_done\n";
    print STDERR "\n\n$tests_done: $test failed\n";
  }
}