#!perl

use strict;
use warnings;
use Test::More;
use Capture::Tiny ':all';
use Path::Tiny;
use Test::Differences;

BEGIN { use_ok('Preproc::Tiny') };

my @in_files;
my @out_files;
for (1..2) {
	push @in_files,  "test.$_.c.pp";
	push @out_files, "test.$_.c";
}

sub write_input {
	my($in) = @_;
	for (@in_files) {
		path($_)->spew($in);
	}
}

sub check_output {
	my($out) = @_;
	for (@out_files) {
		ok -f $_;
		eq_or_diff $out, path($_)->slurp;
	}
}

sub test {
	my($in, $out) = @_;
	
	local $SIG{__WARN__} = sub { warn @_ unless $_[0] =~ /redefined/ }; # sub dup redefined on each pp_text() call

	# test pp
	write_input($in);
	
	ok 1, "line ".(caller)[2]." - call script";
	unlink @out_files;
	capture_stderr { ok 0 == system $^X, 'blib/script/pp', @in_files };
	check_output($out);
	
	ok 1, "line ".(caller)[2]." - use module old interface";
	unlink @out_files;
	pp(@in_files);
	check_output($out);
	
	ok 1, "line ".(caller)[2]." - use module new interface";
	unlink @out_files;
	pp_files(@in_files);
	check_output($out);
	
	unlink @in_files, @out_files;
	
	# test filter
	my $result = pp_text($in);
	eq_or_diff $out, $result;
}

test(<<'IN', <<'OUT');
@@sub dup {
@@	$_[0]*2;
@@}
@@my $name = "John Doe";
Hello [@> $name @]!
Hi there [@> $name -@]

!
Howdy [@> $name @]
.
[@ for (1..4) { -@]
	[@> dup($_) @] [@ 
} @]
[@ $OUT .= "xx\n"; @]
IN
Hello John Doe!
Hi there John Doe!
Howdy John Doe
.
2 4 6 8 
xx

OUT


test(<<'IN', <<'OUT');
int main() { return 0; }
IN
int main() { return 0; }
OUT


test(<<'IN', <<'OUT');
@@ my $ret = 0;
int main() { 
  return @@ $OUT .= $ret.";";
}
IN
int main() { 
  return 0;
}
OUT


test(<<'IN', <<'OUT');
[@ 
  use strict;
  use warnings;
  my $ret = 0;
@]
int main() { 
  return [@ $OUT .= $ret @];
}
IN

int main() { 
  return 0;
}
OUT


test(<<'IN', <<'OUT');
[@ 
  use strict;
  use warnings;
  my $ret = 0;
-@]
int main() { 
  return [@ $OUT .= $ret @];
}
IN
int main() { 
  return 0;
}
OUT


test(<<'IN', <<'OUT');
[@ 
  use strict;
  use warnings;
  my $ret = 0;
-@]
int main() { 
  return [@> $ret @];
}
IN
int main() { 
  return 0;
}
OUT


test(<<'IN', <<'OUT');
int main() {
  return 0;  // comment
}
@@ $OUT =~ s!//.*!!g;
IN
int main() {
  return 0;  
}
OUT


test(<<'IN', <<'OUT');
@@ my $ok = 1;
int main() {
  return [@ if ($ok) { @] 0 [@ } else { @] 1 [@ } @];
}
IN
int main() {
  return  0 ;
}
OUT


write_input(<<'IN');
@@ ok=1;
IN


my($stderr, $result) = capture_stderr { system $^X, 'blib/script/pp' };
ok $result != 0;
like $stderr, qr/Usage: pp file\.pp\.\.\./;

($stderr, $result) = capture_stderr { system $^X, 'blib/script/pp', $in_files[0] };
ok $result != 0;
like $stderr, qr/Can't modify constant item in scalar assignment/;
like $stderr, qr/parse error:/;

unlink @in_files, @out_files;
done_testing;
