#
# Copyright (c) 2015-2019 Christian Jaeger, copying@christianjaeger.ch
#
# This is free software, offered under either the same terms as perl 5
# or the terms of the Artistic License version 2 or the terms of the
# MIT License (Expat version). See the file COPYING.md that came
# bundled with this file.
#

=head1 NAME

FP::Equal::t -- tests for FP::Equal

=head1 SYNOPSIS

=head1 DESCRIPTION

run by test suite

=head1 NOTE

This is alpha software! Read the package README.

=cut


package FP::Equal::t;

use strict; use warnings; use warnings FATAL => 'uninitialized';

use FP::Equal ":all";
use Chj::TEST;

# compare arguments both straight and swapped; if the results don't
# match, return an array with both results
sub tequals {
    @_==2 or die "wrong num arg";
    my $x= equaln (@_);
    my $y= equaln (@_);
    if (defined $x) {
        if (defined $y) {
            if ($x eq $y) {
                return $x
            }
        }
    } else {
        if (defined $y) {
            [$x, $y]
        } else {
            undef
        }
    }
}

# from the synopsis
use FP::List;
use FP::Div qw(inc);
TEST{ equal [1, list(2, 3)], [1, list(1, 2)->map(*inc)] } 1;
TEST{ equal [1, list(2, 3)], [1, list(1, 2)] } '';
TEST{ equal [1, list(2, 3)], [1, list([], 3)] } undef;

# 'systematic':
TEST{equal undef, undef} 1;
TEST{equal 1, undef} undef; # really give undef in
TEST{equal undef, 1} undef; #   this case?
TEST{equal 1, 1} 1;
TEST{equal 1, 0} '';
TEST{equal 0, 1} '';
TEST{equal [], 0} undef;
TEST{equal 0, []} undef;
TEST{equal [], []} 1;
TEST{my $v=[]; equal $v, $v} 1;
TEST{equal [], {}} undef;
TEST{equal {}, {}} 1;
TEST{equal {}, {a=>1}} '';
TEST{equal {a=>2}, {a=>1}} '';
TEST{equal {a=>1}, {b=>1}} '';
TEST{equal {a=>1}, {a=>1}} 1;
TEST{equal {a=>1,b=>2}, {a=>1}} '';
TEST{equal {a=>1,b=>2}, {a=>1,b=>2}} 1;
TEST{equal {a=>1,b=>2}, {a=>1,B=>2}} '';
TEST{equal {a=>1,b=>2}, {a=>1,b=>3}} '';
TEST{equal {a=>[1,3]}, {a=>[1,2+1]}} 1;
TEST{equal {a=>[1,3]}, {a=>[1,2]}} '';

TEST{equal "a", "b"} '';
TEST{equal "a", "a"} 1;

# Perl just can't disambiguate between numbers and strings, don't try
# to fight it?
TEST{tequals "2", 2} 1;
TEST{tequals "2.0", 2.0} '';

my $inf= $^V->{version}[1] > 20 ?
  # XX where exactly was it changed?
  # v5.14.2: inf
  # v5.21.11-27-g57e8809: Inf
  "Inf" : "inf";

TEST{tequals 1e+20000, $inf} 1;
TEST{ 1e+20000 == "inf" } 1;
TEST{tequals 1/(-1e+2000), 1/(1e+2000) } 1;
TEST{ 1/(-1e+2000) == 1/(1e+2000) } 1;
# so, no need to have both eq and == for those cases!

# but that's not the case here, of course:
TEST{ -1e1000 == "-1e1000" } 1;
TEST{ -1e1000 eq "-1e1000" } '';
TEST{ tequals -1e1000, "-1e1000" } '';
TEST{ tequals -1e1000, "-$inf" } 1;
TEST{ -1e1000 == "-inf" } 1;

TEST{tequals 2, 2.0} 1;    # those are converted to the same value at
                           # compile time.
TEST{tequals "2", "2.0"} '';

# Weak typing is where the data (or context of the language) doesn't
# say what it is.

TEST{tequals \("foo"), \("f"."oo")} 1;
TEST{tequals \("foo"), \("bar")} '';
TEST{my $x= undef;
     my $y= undef;
     tequals \$x, \$y} 1;
TEST{my $x= "foo";
     my $y= undef;
     tequals \$x, \$y} undef;

# globs
TEST{tequals *foo::bar, "*foo::bar"} undef;
TEST{tequals ((*foo::bar)."", "*foo::bar")} 1;
TEST{tequals *foo, *FP::Equal::t::foo} 1;
TEST{tequals \*foo, \*FP::Equal::t::foo} 1;
TEST{tequals \(*foo::bar), \("*foo::bar")} undef;
TEST{tequals \(*foo::bar), \(*foo::baz)} '';
TEST{tequals *foo, *bar} '';


# filehandles
TEST{equal *STDIN{IO}, *STDIN{IO}} 1; # equal pointers
TEST_EXCEPTION {equal *STDIN{IO}, *STDOUT{IO}}
  q{Can't locate object method "FP_Equal_equal" via package "IO::File"};


# encoding
use utf8;
{
    my ($s1,$s2);
    TEST{$s1= "Smørrebrød";
         $s2= "Smørrebrød";
         equal $s1, $s2} 1;
    TEST{utf8::encode($s2);
         equal $s1, $s2} '';
}


# Lazy values, classes:
use FP::Stream;
use FP::Lazy;

TEST {tequals "a", lazy { chr 65+32 } } 1;
TEST {tequals stream (1,2), stream (1,2)} 1;
TEST {tequals stream (1,2), lazy { cons 1, stream (2)}} 1;
TEST {tequals stream (1,2), cons 1, stream (2)} 1;

# only one of the arguments lazy:

TEST { tequals lazy { 2+1 }, 1+2 } 1;

TEST { tequals lazy { [2+1] }, [lazy { 1+2 }] } 1;
TEST { tequals lazy { [2+1] }, [lazy { 1+3 }] } '';

TEST { tequals lazy { 2+1 }, [1+2] } undef;
TEST { tequals lazy { [2+1] }, 1+2 } undef;

# does it force identical promises?

my ($a,$b,$sideeffect);
TEST { $sideeffect= 0;
       $a= lazy { $sideeffect++; 33*3 };
       $b= $a;
       tequals $a, $b
   } 1;
TEST { $sideeffect } 0;

TEST { $sideeffect= 0;
       $a= lazy { $sideeffect++; 33*3 };
       $b= lazy { $sideeffect++; 33*3 };
       tequals $a, $b
   } 1;
TEST { $sideeffect } 2;

# lazy and undef or non-references:

TEST { tequals lazy { undef }, undef } 1;
TEST { tequals lazy { "a" }, "a" } 1;
TEST { tequals lazy { "a" }, undef } undef;
TEST { tequals lazy { undef }, "a" } undef;

1
