Class-Scaffold

 view release on metacpan or  search on metacpan

lib/Class/Scaffold/App/Test/YAMLDriven.pm  view on Meta::CPAN

__PACKAGE__->mk_abstract_accessors(qw(run_subtest plan_test))
  ->mk_hash_accessors(qw(test_def))->mk_scalar_accessors(
    qw(
      testdir testname expect run_num runs current_test_def
      )
  );
use constant SHARED => '00shared.yaml';
use constant GETOPT => (
    qw/
      shuffle reverse
      /
);

# 'runs' is the number of stage runs per test file ensure idempotency
use constant DEFAULTS => (
    runs    => 1,
    testdir => '.',
);

sub app_code {
    my $self = shift;
    $self->SUPER::app_code(@_);
    $self->read_test_defs;
    plan tests => $self->make_plan;
    for my $testname ($self->ordered_test_def_keys) {
        next if $testname eq SHARED;
        $self->execute_test_def($testname);
    }
}

sub read_test_defs {
    my $self = shift;

    # It's possible to pass args to the test program. If there are any
    # such args, then in order for a test file to be used its name has to
    # contain one of the args as a substring. For example, to only run
    # the policy tests whose name contains 'unnamed' or '99', you'd use:
    #
    #   perl t/10Policy.t unnamed 99
    my $name_filter = join '|' => map { "\Q$_\E" } @ARGV;
    my $testdir = $self->testdir;

    # First collect the files to process into a hash, then process that
    # hash sorted by name. This separation is necessary because some test
    # files depend on others, but find() doesn't ensure that the files are
    # returned in sorted order.
    my %file;
    find(
        sub {
            return unless -f && /\.yaml$/;
            (my $name = $File::Find::name) =~ s!^$testdir/!!;
            return
              if $name ne SHARED && $name_filter && $name !~ /$name_filter/o;
            $file{$name} = $File::Find::name;
        },
        $testdir
    );
    for my $name (sort keys %file) {
        note "Loading test file $name";
        (   my $tests_yaml =
              do { local (@ARGV, $/) = $file{$name}; <> }
        ) =~ s/%%PID%%/sprintf("%06d", $$)/ge;
        $tests_yaml =~ s/%%CNT%%/sprintf("%03d", ++(our $cnt))/ge;

        # Quick regex check whether the test wants to be skipped. To use
        # Load() on a test that wants to be skipped would be a bad idea as it
        # might be work in progress; it will be skipped for a reason.
        if ($tests_yaml =~ /^skip:\s*1/m) {
            note 'Test wants to be skipped, no activation';
        } else {

            # support for value classes
            local $Class::Value::SkipChecks = 1;

            # require(), not use(), YAML classes because YAML and YAML::Active
            # might conflict.
            my $test_def;
            if ($tests_yaml =~ /^use_yaml_active:\s*1/m) {
                note 'Loading with YAML::Active.pm';
                require YAML::Active;
                $test_def = YAML::Active::Load($tests_yaml);
            } else {
                require YAML;

                # Erik P. Ostlyngen writes:
                #
                # There seems to be a difference in the behaviour of YAML and
                # YAML::XS when it comes to wide characters. YAML::Load()
                # wants the string to be a perl wide character string whereas
                # YAML::XS::Load() wants a string of bytes which it tries to
                # utf-8 decode afterwards.
                #
                # This is a problem in Class::Scaffold::App::Test::YAMLDriven
                # because it uses both of the two YAML modules. So if we're
                # writing our tests with the use_yaml_active tag, we can
                # include utf-8 in the document. But if we instead use YAML
                # with the marshall classes, we cannot use utf-8 directly.
                #
                # I think it would be a good idea to support utf-8 encoding
                # both in yaml-active and yaml-marshall documents and in the
                # same way. This could easily be fixed with [decode_utf8()].
                $test_def = YAML::Load(decode_utf8($tests_yaml));

                # note explain $test_def;
            }
            $self->test_def($name => $test_def);
        }
    }
}

sub ordered_test_def_keys {
    my $self = shift;
    my @tests;
    if ($self->opt->{shuffle}) {
        note 'test order: shuffle';
        @tests = shuffle $self->test_def_keys;
    } elsif ($self->opt->{reverse}) {
        note 'test order: reverse';
        @tests = reverse sort $self->test_def_keys;
    } else {
        note 'test order: sort';



( run in 2.041 seconds using v1.01-cache-2.11-cpan-98e64b0badf )