##
## Pixie::Proxy::ARRAY tests
##

use lib 't/lib';
use blib;
use strict;
use warnings;

use Test::More qw( no_plan );
use Test::Exception;

BEGIN { local $TODO = 'separate embedded subclasses';
	use_ok( 'Pixie::Proxy::Overloaded' ); }
BEGIN { use_ok( 'Pixie::Proxy' ); }

#-----------------------------------------------------------------------------
# Fallback undefined

## explicitly overloaded ops
{
    my $hv    = MyOverloadedHash->new;
    my $proxy = Pixie::Proxy::Overloaded::Test->new
      ->_oid( 'hv' )
      ->stored_obj( $hv )
      ->px_class( ref( $hv ) );

    like( "$proxy",
	  qr/"",MyOverloadedHash=.+/,
	  'proxies explicitly overloaded ops ("")' );
}

## magic autogenerated methods
{
    my $hv    = MyOverloadedHash::WithAutoGen->new;
    my $proxy = Pixie::Proxy::Overloaded::Test->new
      ->_oid( 'hv' )
      ->stored_obj( $hv )
      ->px_class( ref( $hv ) );

    is( $proxy . " test",
	"stringify test",
	'proxies autogenerated ops (concat)' );
}

## ops overloaded with 'nomethod'
TODO: {
    my $hv    = MyOverloadedHash::WithNoMethod->new;
    my $proxy = Pixie::Proxy::Overloaded::Test->new
      ->_oid( 'hv' )
      ->stored_obj( $hv )
      ->px_class( ref( $hv ) );

    local $TODO = 'shouldnt die on overloading with nomethod';
    lives_ok {
    like( 1 + $proxy,
	  qr/no method,MyOverloadedHash::WithNoMethod=.+/,
	  'proxies ops overloaded with nomethod (+)' );
    };
}

## explicitly overloaded ops, no fallback
{
    my $hv    = MyOverloadedHash::NoFallback->new;
    my $proxy = Pixie::Proxy::Overloaded::Test->new
      ->_oid( 'hv' )
      ->stored_obj( $hv )
      ->px_class( ref( $hv ) );

    like( "$proxy",
	  qr/"",MyOverloadedHash::NoFallback=.+/,
	  'proxies explicitly overloaded ops ("") with fallback => 0' );
}

## ops overloaded with 'nomethod', no fallback
TODO: {
    my $hv    = MyOverloadedHash::WithNoMethod->new;
    my $proxy = Pixie::Proxy::Overloaded::Test->new
      ->_oid( 'hv' )
      ->stored_obj( $hv )
      ->px_class( ref( $hv ) );

    local $TODO = 'shouldnt die on overloading with nomethod, no fallback';
    lives_ok {
    like( 1 + $proxy,
	  qr/no method,MyOverloadedHash::WithNoMethod::NoFallback=.+/,
	  'proxies ops overloaded with nomethod (+), with fallback => 0' );
    };
}

## test internal 'FALLBACK' uses Proxy obj when called within Pixie
{
    my $hv    = MyOverloadedHash::Nothing->new;
    my $proxy = Pixie::Proxy::Overloaded::Test->new
      ->_oid( 'hv' )
      ->stored_obj( $hv )
      ->px_class( ref( $hv ) );

    like( $proxy->call_stringify,
	  qr/Pixie::Proxy::Overloaded::Test=.+/,
	  '"" operator fallback, called from Pixie' );

    like( $proxy->call_concat_str( 'test' ),
	  qr/Pixie::Proxy::Overloaded::Test=.+test/,
	  '. operator fallback, called from Pixie' );

    ok( !$proxy->call_bool_not, ' ! operator fallback, called from Pixie' );
    ok( $proxy->call_bool,      'bool operator fallback, called from Pixie' );
}

## test internal 'FALLBACK' uses real obj when called externally
TODO: {
    my $hv    = MyOverloadedHash::Nothing->new;
    my $proxy = Pixie::Proxy::Overloaded::Test->new
      ->_oid( 'hv' )
      ->stored_obj( $hv )
      ->px_class( ref( $hv ) );

    local $TODO = 'these should work';
    like( "$proxy",
	  qr/MyOverloadedHash::Nothing=.+/,
	  '"" operator fallback, called externally' );

    like( $proxy . 'test',
	  qr/MyOverloadedHash::Nothing=.+test/,
	  '. operator fallback, called externally' );

    lives_ok {
    ok( !$proxy,        ' ! operator fallback, called externally' );
    } 'internal FALLBACK uses real obj when called externally';
    lives_ok {
    ok( $proxy ? 1 : 0, 'bool operator fallback, called externally' );
    } 'internal FALLBACK uses real obj when called externally';
}


#-----------------------------------------------------------------------------
# This subclass bypasses Pixie, letting us test the overloading proxy methods

package Pixie::Proxy::Overloaded::Test;

use base qw( Pixie::Proxy::Overloaded );
use accessors qw( px_class _oid stored_obj );
use vars qw( @ISA );
BEGIN { push( @ISA, 'Pixie::Proxy' ) };  # avoid loading Pixie::Proxy itself
sub new { bless {}, $_[0]; }

sub px_the_store {
    # do nothing, for DESTROY
}

sub px_restore {
    my $self       = shift;
    my $stored_obj = $self->stored_obj;
    %{ $self }     = %{ $stored_obj };
    bless $self, ref( $stored_obj );
}

sub call_bool_not   { return ! $_[0]  }
sub call_bool       { return $_[0] ? 1 : undef }
sub call_concat_str { return $_[0] . $_[1] }
sub call_stringify  { "$_[0]" }


#-----------------------------------------------------------------------------
# These classes test various forms of overloading

package MyOverloadedHash::Base;
use Pixie::Complicity;
sub new { bless {}, $_[0]; }
sub main::string_args { join(',', map {overload::StrVal( $_ )} @_) }

package MyOverloadedHash;
use base qw( MyOverloadedHash::Base );
use overload
  '""'     => sub{ main::string_args( '""', @_ ) };

package MyOverloadedHash::Nothing;
use base qw( MyOverloadedHash::Base );
use overload fallback => 1;

package MyOverloadedHash::WithNoMethod;
use base qw( MyOverloadedHash::Base );
use overload
  fallback => 1,
  nomethod => sub{ main::string_args( 'no method', @_ ) };

package MyOverloadedHash::WithAutoGen;
use base qw( MyOverloadedHash::Base );
use overload
  fallback => 1,
  '""'     => sub { 'stringify' };

package MyOverloadedHash::NoFallback;
use base qw( MyOverloadedHash::Base );
use overload
  fallback => 0,
  '""'     => sub{ main::string_args( '""', @_ ) };

package MyOverloadedHash::WithNoMethod::NoFallback;
use base qw( MyOverloadedHash::Base );
use overload
  fallback => 0,
  nomethod => sub{ main::string_args( 'no method', @_ ) };

