#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
use Test::More;
use Test::Exception;
use Data::Dumper;
use File::Temp 'tempfile';

use Data::Resolver qw< :transformers >;

my $data = 'whatever';

subtest 'from data to...' => sub {
   check_filehandle(data_to_fh($data));
   check_file(data_to_file($data)); # defaults to not keep it
};

my $filename;
lives_ok {
   (my $fh, $filename) = tempfile(UNLINK => 1);
   print {$fh} $data or die $!;
   close $fh or die $!;
} 'saving a temporary file, for testing';

subtest 'from file to...' => sub {
   check_filehandle(file_to_fh($filename));
   check_data(file_to_data($filename));
};

subtest 'from filehandle to...' => sub {
   my $fh;

   check_file(fh_to_file($fh = __open($filename)));
   close $fh;

   check_data(fh_to_data($fh = __open($filename)));
   close $fh;
};

subtest 'persistence of files' => sub {
   my $path;

   $path = forked_data_to_file($data, 0); # don't keep
   ok length($path // ''), 'got path from the child process';
   ok ! -e $path, 'path does not exist any more';

   $path = forked_data_to_file($data, 1); # do keep
   ok length($path // ''), 'got path from the child process';
   ok -e $path, 'path persisted';
   unlink $path;
};

subtest 'transform to filehandle' => sub {
   check_filehandleref(transform($data,     qw< data fh >));
   check_filehandleref(transform($data,     qw< data filehandle >));
   check_filehandleref(transform($filename, qw< file fh >));
   check_filehandleref(transform($filename, qw< file filehandle >));
   check_filehandleref(transform($filename, qw< path fh >));
   check_filehandleref(transform($filename, qw< path filehandle >));
};

subtest 'transform to file' => sub {
   check_fileref(transform($data, qw< data file >));
   check_fileref(transform($data, qw< data path >));
   check_fileref(transform(__open($filename), qw< fh         file >));
   check_fileref(transform(__open($filename), qw< fh         path >));
   check_fileref(transform(__open($filename), qw< filehandle file >));
   check_fileref(transform(__open($filename), qw< filehandle path >));
};

subtest 'transform to data' => sub {
   check_dataref(transform($filename, qw< file data >));
   check_dataref(transform($filename, qw< path data >));
   check_dataref(transform(__open($filename), qw< fh         data >));
   check_dataref(transform(__open($filename), qw< filehandle data >));
};

done_testing();

sub __open ($file) {
   open my $fh, '<:raw', $file or die $!;
   return $fh;
}

sub check_filehandle ($fh) {
   ok $fh, 'got something';
   is ref($fh), 'GLOB', 'got a filehandle';
   my $got = do { local $/; <$fh> };
   is $got, $data, 'data from the filehandle';
}

sub check_filehandleref ($got) {
   is ref($got), 'REF', 'REF ref';
   return check_filehandle($$got);
}

sub check_file ($file) {
   ok length($file // ''), 'data_to_file returned something';
   is ref($file), '', 'returned a string';
   ok -e $file, 'file exists';
   my $got = do { local (@ARGV, $/) = ($file); <> };
   is $got, $data, 'reading from the file';
}

sub check_fileref ($got) {
   is ref($got), 'SCALAR', 'SCALAR ref';
   return check_file($$got);
}

sub check_data ($got) {
   ok length($got // ''), 'file_to_data returned something';
   is $got, $data, 'data from file';
}

sub check_dataref ($got) {
   is ref($got), 'SCALAR', 'SCALAR ref';
   return check_data($$got);
}

sub forked_data_to_file ($data, $keep) {
   pipe my $rfh, my $wfh or die "pipe(): $!";
   my $pid = fork() // die "fork(): $!";
   if ($pid) { # parent process
      close $wfh;
      my ($filename) = <$rfh>;
      close $rfh;
      wait;
      return $filename;
   }
   else {
      close $rfh;
      my $path = data_to_file($data, $keep);
      print {$wfh} $path;
      close $wfh;
      exit 0;
   }
}
