#!perl -w   -- -*- tab-width: 4; mode: perl -*-

use strict;
use warnings;

use Test::More;				# included with perl
use Test::Differences;		# included with perl

my $haveTestNoWarnings = eval { require Test::NoWarnings; import Test::NoWarnings; 1; };

if ( !$ENV{HARNESS_ACTIVE} ) {
	# not executing under Test::Harness
	use lib qw{ blib/arch };	# only needed for dynamic module loads (eg, compiled XS) [ remove if no XS ]
	use lib qw{ lib };			# use the 'lib' version (for ease of testing from command line and testing immediacy; so 'blib/arch' version doesn't have to be built/updated 1st)
	}

use Win32::CommandLine;

sub add_test;
sub test_num;
sub do_tests;

# Tests

## accumulate tests

# TODO: organize tests, add new tests for 'xx.bat'
add_test( [ qq{$0 }.q{-m "VERSION: update to 0.3.11"} ], ( q{-m}, q{VERSION: update to 0.3.11} ) );
add_test( [ qq{$0 }.q{-m "VERSION: update to 0.3.11"}, {dosquote => 1} ], ( q{-m}, q{"VERSION: update to 0.3.11"} ) );

add_test( [ qq{$0 }.q{'"'} ], ( q{"} ) ); 	#"
#add_test( [ qq{$0 }.q{'"'}, { dosify => 1 }  ], ( q{"\\""} ) ); 	#"
#add_test( [ qq{$0 }.q{"\\""}, { dosify => 1 }  ], ( q{"\\""} ) ); 	#"
add_test( [ qq{$0 }.q{'"'}, { dosquote => 1 }  ], ( q{"\\""} ) ); 	#"
add_test( [ qq{$0 }.q{"\\""}, { dosquote => 1 }  ], ( q{"\\""} ) ); 	#"

add_test( [ qq{$0 }.q{$""} ], ( q{} ) );
add_test( [ qq{$0 }.q{$'\x25'} ], ( q{%} ) );

add_test( [ qq{$0 }.q{$'test'} ], ( q{test} ) );
add_test( [ qq{$0 }.q{$"test"} ], ( q{test} ) );
add_test( [ qq{$0 }.q{'"test"'} ], ( q{"test"} ) );

add_test( [ qq{$0} ], qw( ) );

add_test( [ qq{ $0} ], qw( ) );

add_test( [ qq{$0 } ], qw( ) );

add_test( [ qq{ $0 } ], qw( ) );

add_test( [ qq{ a } ], qw( ) );

add_test( [ qq{ a b c } ], qw( ) );

add_test( [ qq{ a 'b' c } ], qw( ) );

add_test( [ qq{$0 a '' } ], ( qq{a}, qq{} ) );

add_test( [ qq{$0 a b c} ], qw( a b c ) );

add_test( [ qq{$0 "a b" c} ], ( 'a b', 'c' ) );

add_test( [ qq{$0 'a b' c'' } ], ( "a b", "c" ) );

add_test( [ qq{$0 "a b" c"" } ], ( "a b", "c" ) );

add_test( [ qq{$0 "a b" c""d } ], ( "a b", "cd" ) );

add_test( [ qq{$0 'a'b c''d } ], ( 'ab', 'cd' ) );

add_test( [ qq{$0 a'b'c''d } ], ( 'abcd' ) );

add_test( [ qq{$0 "a"b c""d } ], ( 'ab', 'cd' ) );

add_test( [ qq{$0 a"b"c""d } ], ( 'abcd' ) );

add_test( [ qq{$0 "a"b c''d } ], ( 'ab', 'cd' ) );

add_test( [ qq{$0 a"b"c''d } ], ( 'abcd' ) );

add_test( [ qq{$0 'a'b c""d } ], ( 'ab', 'cd' ) );

add_test( [ qq{$0 a'b'c""d } ], ( 'abcd' ) );

add_test( [ qq{$0 'a b" c'} ], ( qq{a b" c} ) );	##"

add_test( [ qq{$0 'a bb" c'} ], ( qq{a bb" c} ) );		##"

add_test( [ qq{$0 \$'test'} ], ( qq{test} ) );

add_test( [ qq{$0 \$'\\x34\\x34'} ], ( qq{44} ) );

add_test( [ qq{$0 '\\x34\\x34'} ], ( qq{\\x34\\x34} ) );

add_test( [ qq{$0 \*.t} ], ( q{*.t} ) );

add_test( [ qq{$0 '*.t} ], ( q{Unbalanced command line quotes [#1] (at token`'*.t` from command line `}.qq{$0}.q{ '*.t`)} ) );

add_test( [ qq{$0 a b c \*.t} ], ( qw{a b c}, q{*.t} ) );

add_test( [ qq{$0 a b c t/\*.t} ], ( qw{a b c}, glob('t/*.t') ) );

add_test( [ qq{$0 a t/\*.t b} ], ( "a", glob('t/*.t'), "b" ) );

add_test( [ qq{$0 t/\"*".t} ], ( q{t/*.t} ) );		##"

add_test( [ qq{$0 t/\'*'.t} ], ( q{t/*.t} ) );

add_test( [ qq{$0 t/{0}\*.t} ], ( glob('t/{0}*.t') ) );

add_test( [ qq{$0 t/{0,}\*.t} ], ( glob('t/{0,}*.t') ) );

add_test( [ qq{$0 t/{0,p}\*.t}, { 'nullglob' => 1 } ], ( glob('t/{0,p}*.t') ) );

add_test( [ qq{$0 t/\{0,t,p\}\*.t}, { 'nullglob' => 1 } ], ( glob('t/{0,t,p}*.t') ) );

add_test( [ qq{$0 t/\{t,p,0\}\*.t}, { 'nullglob' => 1 } ], ( glob('t/{t,p,0}*.t') ) );

add_test( [ qq{$0 t/\*} ], ( glob('t/*') ) );

add_test( [ qq{$0 '\\\\'} ], ( '\\\\' ) );

add_test( [ qq{$0 'a\\a' '\\a\\x\\'} ], ( 'a\\a', '\\a\\x\\' ) );

add_test( [ qq{$0 '/a\a'} ], ( qq{/a\a} ) );

add_test( [ qq{$0 '//foo\\bar'} ], ( q{//foo\\bar} ) );

add_test( [ qq{$0 '/a\a' /foo\\\\bar} ], ( qq{/a\a}, q{/foo\\\\bar} ) );

add_test( [ qq{$0 1 't\\glob-file.tests'/*} ], ( 1, glob('t/glob-file.tests/*') ) );

add_test( [ qq{$0 2 't\\glob-file.tests'\\*} ], ( 2, glob('t/glob-file.tests/*') ) );

add_test( [ qq{$0 3 't\\glob-file.tests/'*} ], ( 3, glob('t/glob-file.tests/*') ) );

add_test( [ qq{$0 4 't\\glob-file.tests\\'*} ], ( 4, glob('t/glob-file.tests/*') ) );

add_test( [ qq{$0 5 't\\glob-file.tests\\*'} ], ( 5, q{t\\glob-file.tests\\*} ) );

add_test( [ qq{$0 t ""} ], ( q{t}, q{} ) );

add_test( [ qq{$0 t 0} ], ( q{t}, q{0} ) );

add_test( [ qq{$0 t 0""} ], ( q{t}, q{0} ) );

add_test( [ qq{$0 't\\glob-file.tests\\'*x} ], ( q{t\\glob-file.tests\\*x} ) );

# TODO BUG: "\\loish\Shared Documents"\* => "\\loish\Shared Documents" and glob of '\*'
# TODO: create tests for above
# TODO: create tests for "\\127.0.0.1\"...

## ?? change to include here surrounded by $ENV{TEST_FRAGILE} check? or do skipped tests need to be in a specific file by themselves?
### TODO: this is really not a fair test on all computers unless we make sure the specific account(s) exist and know what the expansion should be...
### TEST_FRAGILE == tests which require a specific environment setup to work
### use TEST_FRAGILE
if ($ENV{TEST_FRAGILE} or ($ENV{TEST_ALL} and (defined $ENV{TEST_FRAGILE} and $ENV{TEST_FRAGILE}))) {
	# SLIGHTLY-FRAGILE
	add_test( [ qq{$0 }.q{c:/{windows}}, { dosify => 1 } ], ( q{c:\\windows} ) );
	add_test( [ qq{$0 }.q{c:/{documents}*}, { dosify => 1 } ], ( q{"c:\\Documents and Settings"} ) );
	add_test( [ qq{$0 }.q{c:\\{windows}}, { dosify => 1 } ], ( q{c:\\windows} ) );
	add_test( [ qq{$0 }.q{c:\\{documents}*}, { dosify => 1 } ], ( q{"c:\\Documents and Settings"} ) );
	add_test( [ qq{$0 }.q{"c:\\"win*} ], ( q{Unbalanced command line quotes [#1] (at token`"c:\\"win*` from command line `}.qq{$0}.q{ "c:\\"win*`)} ) );		##"
	add_test( [ qq{$0 }.q{"c:\\"win*}, { dosify => 1 } ], ( q{Unbalanced command line quotes [#1] (at token`"c:\\"win*` from command line `}.qq{$0}.q{ "c:\\"win*`)} ) );
	#
	add_test( [ qq{$0 ~*} ], ( q{~*} ) );
	add_test( [ qq{$0 ~*}, { dosify => 1 } ], ( q{~*} ) );
	add_test( [ qq{$0 ~} ], ( q{C:/Documents and Settings/Administrator} ) );
	add_test( [ qq{$0 ~}, { dosify => 1 } ], ( q{"C:\\Documents and Settings\\Administrator"} ) );
	add_test( [ qq{$0 ~ ~administrator} ], ( q{C:/Documents and Settings/Administrator}, q{C:/Documents and Settings/Administrator} ) );
	add_test( [ qq{$0 ~ ~administrator}, { dosify => 1 } ], ( q{"C:\\Documents and Settings\\Administrator"}, q{"C:\\Documents and Settings\\Administrator"} ) );
	add_test( [ qq{$0 ~administrator/} ], ( q{C:/Documents and Settings/Administrator/} ) );
	add_test( [ qq{$0 ~administrator/}, { dosify => 1 } ], ( q{"C:\\Documents and Settings\Administrator\\"} ) );
	add_test( [ qq{$0 x ~administrator\\ x} ], ( 'x', q{C:/Documents and Settings/Administrator/}, 'x' ) );
	add_test( [ qq{$0 x ~administrator\\ x}, { dosify => 1 } ], ( 'x', q{"C:\\Documents and Settings\\Administrator\\"}, 'x' ) );
	add_test( [ qq{$0 ~"administrator"} ], ( q{C:/Documents and Settings/Administrator} ) );
	add_test( [ qq{$0 ~"administrator"}, { dosify => 1 } ], ( q{"C:\\Documents and Settings\\Administrator"} ) );
	add_test( [ qq{$0 ~"administrator"/} ], ( q{C:/Documents and Settings/Administrator/} ) );
	add_test( [ qq{$0 ~"administrator"/}, { dosify => 1 } ], ( q{"C:\\Documents and Settings\\Administrator\\"} ) );
	add_test( [ qq{$0 ~"administrator"test} ], ( q{~administratortest} ) );
	add_test( [ qq{$0 ~"administrator"test}, { dosify => 1 } ], ( q{~administratortest} ) );

	add_test( [ qq{$0 }.q{\\\\sethra\\C$\\WIND*} ], ( q{//sethra/C$/WINDOWS} ) );
	add_test( [ qq{$0 }.q{"\\\\sethra\\C$"\\WIND*} ], ( q{//sethra/C$/WINDOWS} ) );
	add_test( [ qq{$0 }.q{\\\\sethra/C$/WIND*} ], ( q{//sethra/C$/WINDOWS} ) );
	add_test( [ qq{$0 }.q{"\\\\sethra/"C$/WIND*} ], ( q{//sethra/C$/WINDOWS} ) );
	add_test( [ qq{$0 }.q{//sethra/C$/WIND*} ], ( q{//sethra/C$/WINDOWS} ) );
	add_test( [ qq{$0 }.q{"//sethra/C$/"WIND*} ], ( q{//sethra/C$/WINDOWS} ) );
	add_test( [ qq{$0 }.q{\\\\sethra\\C$\\WIND*}, { dosify => 1 }  ], ( q{\\\\sethra\\C$\\WINDOWS} ) );
	add_test( [ qq{$0 }.q{"\\\\sethra\\C$"\\WIND*}, { dosify => 1 }  ], ( q{\\\\sethra\\C$\\WINDOWS} ) );
	add_test( [ qq{$0 }.q{//sethra/C$/WIND*}, { dosify => 1 }  ], ( q{\\\\sethra\\C$\\WINDOWS} ) );
	add_test( [ qq{$0 }.q{"//sethra/C$/"WIND*}, { dosify => 1 }  ], ( q{\\\\sethra\\C$\\WINDOWS} ) );

	add_test( [ qq{$0 }.q{"\\\\sethra\\C$\\"WIND*} ], ( q{Unbalanced command line quotes [#1] (at token`"\\\\sethra\\C$\\"WIND*` from command line `}.qq{$0}.q{ "\\\\sethra\\C$\\"WIND*`)} ) );	##"
	add_test( [ qq{$0 }.q{"\\\\sethra\\C$\\"WIND*}, { dosify => 1 }  ], ( q{Unbalanced command line quotes [#1] (at token`"\\\\sethra\\C$\\"WIND*` from command line `}.qq{$0}.q{ "\\\\sethra\\C$\\"WIND*`)} ) );	##"
	}
###

## TODO: test backslash escapes within quotes (how to output ", \", etc) => {\"} => {"}, {\\"} => {\"}, ...

#add_test( [ qq{$0 }.q{"\\"} ], ( q{\\} ) );					## EVALUATE
#add_test( [ qq{$0 }.q{"\\"}, { dosify => 1 } ], ( q{\\} ) );	## EVALUATE
add_test( [ qq{$0 }.q{"\\\\"} ], ( q{\\} ) );
add_test( [ qq{$0 }.q{"\\\\"}, { dosquote => 1 } ], ( q{\\} ) );
# double-quotes
add_test( [ qq{$0 }.q{"\\""} ], ( q{"}) );
add_test( [ qq{$0 }.q{"\\""}, { dosquote => 1 } ], ( q{"\\""} ) );
#add_test( [ qq{$0 }.q{"\\\\""} ], ( q{\\"},0) );							#CORRECT: ERROR: Unbalanced quotes...
#add_test( [ qq{$0 }.q{"\\\\""}, { dosify => 1 } ], ( q{"\\\\""},0 ) );		#CORRECT: ERROR: Unbalanced quotes...
add_test( [ qq{$0 }.q{"\\\\\\""} ], ( q{\\"} ) );
add_test( [ qq{$0 }.q{"\\\\\\""}, { dosquote => 1 } ], ( q{"\\\\\\""} ) );


# rule tests
# non-globbed tokens should stay the same
add_test( [ qq{$0 1 foo\\bar} ], ( 1, q{foo\\bar} ) );
add_test( [ qq{$0 2 \\foo/bar} ], ( 2, q{\\foo/bar} ) );
add_test( [ qq{$0 1 't\\glob-file.tests\\'*} ], ( 1, glob('t/glob-file.tests/*') ) );

# dosify
add_test( [ qq{$0 foo\\bar} ], ( q{foo\\bar} ) );



## TODO: check both with and without nullglob, including using %opts for argv()
add_test( [ qq{$0 foo\\bar}, { nullglob => 0 } ], ( q{foo\\bar} ) );

## do tests

$ENV{nullglob} = 0;	# setup a known environment

#plan tests => test_num() + ($Test::NoWarnings::VERSION ? 1 : 0);
plan tests => test_num() + ($haveTestNoWarnings ? 1 : 0);

do_tests(); # test re-parsing of command_line() by argv()
##
my @tests;
sub add_test { push @tests, [ (caller(0))[2], @_ ]; return; }		## NOTE: caller(EXPR) => ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller($i);
sub test_num { return scalar(@tests); }
## no critic (Subroutines::ProtectPrivateSubs)
sub do_tests { foreach my $t (@tests) { my $line = shift @{$t}; my @args = @{shift @{$t}}; my @exp = @{$t}; my @got; eval { @got = Win32::CommandLine::_argv(@args); 1; } or ( @got = ( $@ =~ /^(.*)\s+at.*$/ ) ); eq_or_diff \@got, \@exp, "[line:$line] testing: `@args`"; } return; }
