The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!./perl

my $PERLIO;

BEGIN {
    require './test.pl';
    unless ('PerlIO::Layer'->find('perlio')) {
	print $^STDOUT, "1..0 # Skip: not perlio\n";
	exit 0;
    }
    # Makes testing easier.
    env::var('PERLIO' ) = 'stdio' if defined env::var('PERLIO') && env::var('PERLIO') eq '';
    if (defined env::var('PERLIO') && env::var('PERLIO') !~ m/^(stdio|perlio|mmap)$/) {
	# We are not prepared for anything else.
	print $^STDOUT, "1..0 # PERLIO='$(env::var('PERLIO'))' unknown\n";
	exit 0;
    }
    $PERLIO = defined env::var('PERLIO') ?? env::var('PERLIO') !! "(undef)";
}

use Config;

my $DOSISH    = $^OS_NAME =~ m/^(?:MSWin32|os2|dos|NetWare|mint)$/ ?? 1 !! 0;
   $DOSISH    = 1 if !$DOSISH and $^OS_NAME =~ m/^uwin/;
my $NONSTDIO  = defined env::var('PERLIO') && env::var('PERLIO') ne 'stdio'     ?? 1 !! 0;
my $FASTSTDIO = config_value('d_faststdio') && config_value('usefaststdio') ?? 1 !! 0;
my $UTF8_STDIN;
if ($^UNICODE ^&^ 1) {
    if ($^UNICODE ^&^ 64) {
	# Conditional on the locale
	$UTF8_STDIN = $^UTF8LOCALE;
    } else {
	# Unconditional
	$UTF8_STDIN = 1;
    }
} else {
    $UTF8_STDIN = 0;
}
my $NTEST = 32 - (($DOSISH || !$FASTSTDIO) ?? 7 !! 0) - ($DOSISH ?? 5 !! 0)
    + $UTF8_STDIN;

sub PerlIO::F_UTF8 () { 0x00008000 } # from perliol.h

plan tests => $NTEST;

print $^STDOUT, <<__EOH__;
# PERLIO        = $PERLIO
# DOSISH        = $DOSISH
# NONSTDIO      = $NONSTDIO
# FASTSTDIO     = $FASTSTDIO
# UNICODE       = $^UNICODE
# UTF8LOCALE    = $^UTF8LOCALE
# UTF8_STDIN = $UTF8_STDIN
__EOH__

SKIP: do {
    # FIXME - more of these could be tested without Encode or full perl
    skip("miniperl does not have Encode", $NTEST) if env::var('PERL_CORE_MINITEST');

    sub check {
	my @($result, $expected, $id) =  @_;
	# An interesting dance follows where we try to make the following
	# IO layer stack setups to compare equal:
	#
	# PERLIO     UNIX-like                   DOS-like
	#
	# unset / "" unix perlio / stdio [1]     unix crlf
	# stdio      unix perlio / stdio [1]     stdio
	# perlio     unix perlio                 unix perlio
	# mmap       unix mmap                   unix mmap
	#
	# [1] "stdio" if Configure found out how to do "fast stdio" (depends
	# on the stdio implementation) and in Perl 5.8, otherwise "unix perlio"
	#
	if ($NONSTDIO) {
	    # Get rid of "unix".
	    shift $result if $result[0] eq "unix";
	    # Change expectations.
	    if ($FASTSTDIO) {
		$expected[0] = env::var('PERLIO');
	    } else {
		$expected[0] = env::var('PERLIO') if $expected[0] eq "stdio";
	    }
	} elsif (!$FASTSTDIO && !$DOSISH) {
	    splice($result, 0, 2, "stdio")
		if nelems($result) +>= 2 &&
		   $result[0] eq "unix" &&
		   $result[1] eq "perlio";
	} elsif ($DOSISH) {
	    splice($result, 0, 2, "stdio")
		if nelems($result) +>= 2 &&
		   $result[0] eq "unix" &&
		   $result[1] eq "crlf";
	}
	if ($DOSISH && grep { $_ eq 'crlf' }, $expected) {
	    # 5 tests potentially skipped because
	    # DOSISH systems already have a CRLF layer
	    # which will make new ones not stick.
	    $expected = grep { $_ ne 'crlf' }, $expected;
	}
	my $n = nelems $expected;
	is(nelems($result), $n, "$id - layers == $n");
	for my $i (0 .. $n -1) {
	    my $j = $expected[$i];
	    if (ref $j eq 'CODE') {
		ok($j->($result[$i]), "$id - $i is ok");
	    } else {
		is($result[$i], $j,
		   sprintf("$id - $i is \%s",
			   defined $j ?? $j !! "undef"));
	    }
	}
    }

    check(PerlIO::get_layers($^STDIN),
	  $UTF8_STDIN ?? @( "stdio", "utf8" ) !! @( "stdio" ),
	  "STDIN");

    open(my $f, ">:crlf", "afile");

    check( PerlIO::get_layers($f),
	   qw(stdio crlf),
	  "open :crlf");

    binmode($f, ":pop") or die "$^OS_ERROR";

    check(PerlIO::get_layers($f),
	  qw(stdio),
	  ":pop");

    binmode($f, ":raw") or die "$^OS_ERROR";

    check(PerlIO::get_layers($f),
	  @("stdio"),
	  ":raw");

    binmode($f, ":utf8");

    check(PerlIO::get_layers($f),
	  qw(stdio utf8),
	  ":utf8");

    binmode($f, ":bytes");

    check(PerlIO::get_layers($f),
	  @( "stdio" ),
	  ":bytes");

    binmode($f, ":raw :crlf");

    check(PerlIO::get_layers($f),
	  qw(stdio crlf),
	  ":raw:crlf");

    binmode($f, ":raw :encoding(latin1)"); # "latin1" will be canonized

    # 7 tests potentially skipped.
    unless ($DOSISH || !$FASTSTDIO) {
	my @results = PerlIO::get_layers($f, details => 1);

	# Get rid of the args and the flags.
	splice(@results, 1, 2) if $NONSTDIO;

	check(@results,
	      @("stdio",    undef,        sub { @_[0] +> 0 },
		"encoding", "iso-8859-1", sub { @_[0] ^&^ PerlIO::F_UTF8() } ),
	      ":raw:encoding(latin1)");
    }

    binmode($f);

    check(PerlIO::get_layers($f),
	  @("stdio"),
	  "binmode");

    close $f;

    do {
	use open(IN => ":crlf", OUT => ":utf8");

	open $f, "<", "afile";
	open my $g, ">", "afile";

	check(PerlIO::get_layers($f, input  => 1),
	      qw(stdio crlf),
	      "use open IN");
	
	check(PerlIO::get_layers($g, output => 1),
	      qw[stdio utf8],
	      "use open OUT");

	close $f;
	close $g;
    };

    1 while unlink "afile";
};