#!perl

use strict;
use warnings;

use Runops::Hook;
use Test::More 'no_plan';

use Scalar::Util qw(refaddr);

my ( $called, @ops, @refgen_args, @aassign_args );

Runops::Hook::set_hook(sub {
	my ( $hook, $op, $arity, @args ) = @_;

	$called++;

	if ( $op->name eq 'refgen' and @refgen_args < 2 ) {
		push @refgen_args, [ @args ];
	} elsif ( $op->name eq 'aassign' ) {
		push @aassign_args, [ @args ];
	}

	push @ops, $op;
});

my $i;
++$i;

sub foo { sub { $i } };
sub bar { sub { $i } };

Runops::Hook::enable();

++$i;
my $j = $i + 42;

my ( $x, @refs ) = \( 101, [qw/dancing hippies/], 33, \&foo );

$i ? foo() : bar();

if ( foo() || 1 ) {
	$j = "" . $i;
}

Runops::Hook::disable();

++$i;

is( $i, 3, "ops dispatched" );
ok( $called, "hook called" );
ok( scalar(@ops), "cought some ops" );

my %seen_names;
foreach my $op ( @ops ) {
	isa_ok( $op, "B::OP" );
	$seen_names{$op->name}++;
}

foreach my $opname (qw(
	nextstate
	preinc add
	entersub leavesub
	refgen sassign aassign
	padsv padav gv
	cond_expr and or
	const
	anonlist
	concat
)) {
	ok( $seen_names{$opname}, "$opname op seen by hook" );
}

is_deeply( \@refgen_args, [ [ \&foo ], [ $x, @refs ] ], "listop arg capture" );

is( refaddr($refgen_args[1][0]), refaddr($x), "aliasing semantics" );

is_deeply(
	\@aassign_args,
	[[
		[ \$x, \@refs ],   # two lvalues
		[ \$x, \(@refs) ], # four rvalues, passed to the hook by ref
	]],
	"aassign",
);

