Affix

 view release on metacpan or  search on metacpan

builder/Affix/Builder.pm  view on Meta::CPAN

                dry_run     => $dry_run,
                uninst      => $uninst,
                result      => \%res
            ]
        );

        # In the future, I might check the values of %res according to https://metacpan.org/pod/ExtUtils::Install#install
        0;
    }

    method step_realclean () {
        remove_tree( $_,                { verbose => $verbose } ) for qw[blib temp Build _build_params MYMETA.yml MYMETA.json];
        remove_tree( 'infix/build_lib', { verbose => $verbose } );
        $self->_clean_objects;
        0;
    }

    method step_test() {
        $self->step_build() unless -d 'blib';
        require TAP::Harness::Env;
        my %test_args = (
            ( verbosity => $verbose ),
            ( jobs  => $jobs ),
            ( color => -t STDOUT ),
            lib => [ map { rel2abs( catdir( 'blib', $_ ) ) } qw[arch lib] ],
        );
        TAP::Harness::Env->create( \%test_args )->runtests( sort map { $_->stringify } find( qr/\.t$/, 't' ) )->has_errors;
    }

    method step_fuzz(@args) {
        my %args = @args;
        $self->step_build() unless -d 'blib';

        # Fuzz config via env vars (or caller can pass %args)
        my $max_iter     = $ENV{FUZZ_MAX_ITER} // $args{iter}    // 10000;
        my $timeout      = $ENV{FUZZ_TIMEOUT}  // $args{timeout} // 5;
        my $verbose_fuzz = $ENV{FUZZ_VERBOSE}  // $args{verbose} // 0;

        # Determine which Perl targets to run
        my @targets;
        if ( $args{all} ) {
            @targets = qw[wrap grammar register cross compile];
        }
        elsif ( $args{smoke} ) {
            @targets = qw[wrap grammar register cross];
        }
        elsif ( $args{target} ) {
            @targets = ref $args{target} ? @{ $args{target} } : ( $args{target} );
        }
        else {
            @targets = qw[wrap grammar register cross];
        }

        # Perl fuzz target metadata
        my %perl_targets = (
            wrap     => { script => 'fuzz_wrap_type_sig.pl',  desc => 'Affix::Wrap::Type->parse()',          needs_lib => 1 },
            grammar  => { script => 'fuzz_grammar_mutate.pl', desc => 'Grammar-aware C sig mutations',       needs_lib => 1, extra_inc => 1 },
            register => { script => 'fuzz_register_types.pl', desc => 'Affix::_typedef() — C parser direct', needs_lib => 1 },
            cross    => { script => 'fuzz_cross_boundary.pl', desc => 'Cross-boundary Perl->C->JIT',         needs_lib => 1 },
            compile  => { script => 'fuzz_compile_ok.pl',     desc => 'compile_ok() C compilation',          needs_lib => 1 },
            shared   => { script => 'fuzz_shared_lib.pl',     desc => 'Compile→load→affix→call→verify ABI',  needs_lib => 1 },
        );

        # C fuzz targets (delegate to infix/build.pl)
        my %c_targets = (
            signature  => 'Parser crashes + arena stress',
            abi        => 'ABI classification',
            types      => 'Type generator bugs',
            roundtrip  => 'Type->String->Type consistency',
            trampoline => 'JIT trampoline creation',
            direct     => 'Direct marshalling JIT',
        );
        my $fuzz_dir = path('fuzz');
        die "fuzz/ directory not found\n" unless -d $fuzz_dir;
        my $failures = 0;
        my $iters    = $args{smoke} ? 100 : $max_iter;
        my $to       = $args{smoke} ? 3   : $timeout;

        # Run Perl fuzz targets via TAP::Harness for proper TAP output
        require TAP::Harness::Env;
        my @fuzz_scripts;
        for my $name (@targets) {
            my $target = $perl_targets{$name} // do { warn "Unknown Perl fuzz target: $name\n"; $failures++; next };
            my $script = $fuzz_dir->child( $target->{script} );
            unless ( -f $script ) {
                warn "Fuzz script not found: $script\n";
                $failures++;
                next;
            }
            say "=" x 60;
            say "Fuzzing: $target->{desc}";
            say "  Script: $target->{script}";
            say "  Iterations: $iters, Timeout: ${to}s";
            say "=" x 60;
            push @fuzz_scripts, $script->stringify;
        }
        if (@fuzz_scripts) {
            local $ENV{FUZZ_MAX_ITER} = $iters;
            local $ENV{FUZZ_TIMEOUT}  = $to;
            local $ENV{FUZZ_VERBOSE}  = $verbose_fuzz;
            my %harness_args
                = ( ( verbosity => $verbose ), ( color => -t STDOUT ), lib => [ map { rel2abs( catdir( 'blib', $_ ) ) } qw[arch lib] ], );
            my $harness = TAP::Harness::Env->create( \%harness_args );
            my $aggr    = $harness->runtests( sort @fuzz_scripts );
            $failures++ if $aggr->has_errors;
            say "";
        }

        # Smoke test: also quick-build C targets if available
        if ( $args{smoke} || $args{all} ) {
            my $build_pl = path('infix/build.pl');
            if ( -f $build_pl ) {
                for my $name ( sort keys %c_targets ) {
                    say "=" x 60;
                    say "Building C fuzz target: fuzz:$name";
                    say "  $c_targets{$name}";
                    say "=" x 60;
                    my $exit = system( $^X, $build_pl->stringify, "fuzz:$name" );
                    $failures++ if $exit != 0;
                    say "";
                }



( run in 1.466 second using v1.01-cache-2.11-cpan-9789f410c06 )