# This file is part of grecs  -*- Autotest -*-
# Copyright (C) 2014-2016 Sergey Poznyakoff
#
# Grecs is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# Grecs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Grecs.  If not, see <http://www.gnu.org/licenses/>.

AT_BANNER(Wordsplit)

m4_pushdef([wspnum],[0])
m4_pushdef([wspid])
m4_pushdef([wspgroupnum])
m4_pushdef([wspgroupname])

m4_pushdef([genkw],[dnl
m4_define([wspid],m4_format([wordsplit%03d wsp%03d],wspnum))dnl
m4_if(wspgroupname,,,[m4_define([wspid],wspid[ ]dnl
m4_format(wspgroupname[ ]wspgroupname[%03d],wspgroupnum))dnl
m4_define([wspgroupnum],m4_incr(wspgroupnum))])dnl
m4_define([wspnum],m4_incr(wspnum))dnl
wspid])

m4_pushdef([WSPGROUP],[
m4_define([wspgroupname],$1)
m4_define([wspgroupnum],0)])

dnl ------------------------------------------------------------
dnl TESTWSP([NAME], [KW = `'], [OPTS], [INPUT], [STDOUT = `'],
dnl         [STDERR = `'], [ENV], [PROLOGUE])
dnl
m4_pushdef([TESTWSP],[
AT_SETUP([$1])
AT_KEYWORDS([wordsplit wsp ]genkw[ $2])
AT_CHECK([$8
$7 wsp $3 <<'EOT'
[$4]
EOT
],
[0],
[$5],
[$6])
AT_CLEANUP
])

dnl ------------------------------------------------------------
dnl The first part reproduces legacy argcv tests
dnl ------------------------------------------------------------

TESTWSP([simple input],[wsp-simple],[],
[1 2 3],
[NF: 3
0: 1
1: 2
2: 3
])

TESTWSP([quoted space],[wsp-quoted],[],
[quoted\ space],
[NF: 1
0: "quoted space"
])

TESTWSP([tab character],[wsp-tab],[],
[a "tab	character"],
[NF: 2
0: a
1: tab\tcharacter
])

WSPGROUP(wsp-escape)
TESTWSP([octal and hex escapes],[],[],
[\157\143\164\141\154\40and\x20\x68\x65\x78],
[NF: 1
0: "octal and hex"
])

TESTWSP([octal and hex escapes 2],[],[],
[\157\143\164\141\154\40 and \x20\x68\x65\x78],
[NF: 3
0: "octal "
1: and
2: " hex"
])

TESTWSP([escape representation],[],[],
[A\x3-\48\39],
[NF: 1
0: A\003-\0048\0039
])

WSPGROUP()

dnl ------------------------------------------------------------
dnl Test worsplit-specific behavior
dnl ------------------------------------------------------------
TESTWSP([append],[wsp-append],[append],
[jeden dwa trzy
cztery
piec szesc],
[NF: 3
0: jeden
1: dwa
2: trzy
NF: 4
0: jeden
1: dwa
2: trzy
3: cztery
NF: 6
0: jeden
1: dwa
2: trzy
3: cztery
4: piec
5: szesc
])

TESTWSP([dooffs],[wsp-doofs ],[dooffs 3 jeden dwa trzy],
[cztery piec],
[NF: 2 (3)
(0): jeden
(1): dwa
(2): trzy
3: cztery
4: piec
])

WSPGROUP(wsp-var)

TESTWSP([variable substitutions: single var],[],[],
[a $FOO test],
[NF: 3
0: a
1: bar
2: test
],
[],
[FOO=bar])

TESTWSP([variable substitutions: concatenated vars],[],
[],
[a $FOO${BAR}ent test],
[NF: 3
0: a
1: stringent
2: test
],
[],
[FOO=str BAR=ing])

TESTWSP([variable substitutions: field splitting],[],[],
[a $FOO test],
[NF: 4
0: a
1: variable
2: substitution
3: test
],
[],
[FOO="variable substitution"])

TESTWSP([variable substitutions: double-quoted variable],[],[],
[a "$FOO" test],
[NF: 3
0: a
1: "variable substitution"
2: test
],
[],
[FOO="variable substitution"])

TESTWSP([variable substitutions: single-quoted variable],[],[],
[a '$FOO' test],
[NF: 3
0: a
1: $FOO
2: test
],
[],
[FOO="variable substitution"])

TESTWSP([undefined variables 1],[],[],
[a $FOO test a${FOO}b],
[NF: 3
0: a
1: test
2: ab
],
[],
[unset FOO;])

TESTWSP([undefined variables 2],[],[keepundef],
[a $FOO test a${FOO}b],
[NF: 4
0: a
1: $FOO
2: test
3: a${FOO}b
],
[],
[unset FOO;])

TESTWSP([warn about undefined variables],[],[warnundef],
[$FOO],
[NF: 0
],
[warning: undefined variable `FOO'
],
[unset FOO;])

TESTWSP([bail out on undefined variables],[],[undef],
[$FOO],
[],
[undefined variable
],
[unset FOO;])

TESTWSP([disable variable expansion],[],[novar],
[$FOO],
[NF: 1
0: $FOO
],
[],
[FOO=bar])

TESTWSP([K/V environment],[wsp-env-kv wsp-env_kv],
[env_kv],
[$FOO a$BAZ],
[NF: 2
0: bar
1: aqux
],
[],
[FOO=bar BAZ=qux])

TESTWSP([nosplit with expansion],[wsp-var-nosplit],[nosplit],
[a $FOO test],
[NF: 1
0: "a variable expansion test\n"
],
[],
[FOO="variable expansion"])

TESTWSP([nosplit without expansion],[],[nosplit novar],
[a $FOO test],
[NF: 1
0: "a $FOO test\n"
],
[],
[FOO="variable expansion"])

TESTWSP([default value (defined)],[],[],
[${FOO:-bar}],
[NF: 1
0: qux
],
[],
[FOO=qux])

TESTWSP([default value],[],[],
[${FOO:-bar}],
[NF: 1
0: bar
])

TESTWSP([default value (defined)],[],[],
[${FOO:-bar}],
[NF: 1
0: qux
],
[],
[FOO=qux])

TESTWSP([default value (:- null)],[],[],
[${FOO:-bar}],
[NF: 1
0: bar
],
[],
[FOO=])

TESTWSP([default value (- null)],[],[],
[${FOO-bar}],
[NF: 0
],
[],
[FOO=])

TESTWSP([default value (- null, unset)],[],[],
[${FOO-bar}],
[NF: 1
0: bar
])

TESTWSP([assign default values],[],[],
[${FOO=bar}
$FOO],
[NF: 1
0: bar
NF: 1
0: bar
])

TESTWSP([default error message (var defined)],[],[],
[a ${FOO:?} test],
[NF: 3
0: a
1: bar
2: test
],
[],
[FOO=bar])

TESTWSP([default error message],[],[],
[${FOO:?}],
[NF: 0
],
[FOO: variable null or not set
])

TESTWSP([custom error message (defined)],[wsp-custom-err wsp-custom-err00],[],
[a ${FOO:?please define it} test],
[NF: 3
0: a
1: bar
2: test
],
[],
[FOO=bar])

TESTWSP([custom error message],[wsp-custom-err wsp-custom-err01],[],
[a ${FOO:?please define it} test],
[NF: 2
0: a
1: test
],
[FOO: please define it
])

TESTWSP([alternate value (defined)],[wsp-alt wsp-alt00],[],
[a ${FOO:+isset} test],
[NF: 3
0: a
1: isset
2: test
],
[],
[FOO=bar])

TESTWSP([alternate value],[wsp-alt wsp-alt01],[],
[a ${FOO:+isset} test],
[NF: 2
0: a
1: test
],
[],
[unset FOO;])

TESTWSP([getvar],[wsp-getvar],
[foo=bar x=quux],
[begin $foo $x end],
[NF: 4
0: begin
1: bar
2: quux
3: end
],
[],
[],
[unset foo; unset x])

TESTWSP([getvar and env],[wsp-getvar],
[foo=bar x=quux y=xur],
[begin $foo $TVAR $x $y end],
[NF: 6
0: begin
1: bar
2: 12
3: quux
4: zwar
5: end
],
[],
[TVAR=12 y=zwar],
[unset foo; unset x])

TESTWSP([getvar, alternate value],[wsp-getvar],
[foo=bar],
[a ${foo:+isset}],
[NF: 2
0: a
1: isset
])

WSPGROUP()

TESTWSP([ignore quotes],[wsp-ignore-quotes ],[-quote],
["a text"],
[NF: 2
0: "\"a"
1: "text\""
])

WSPGROUP(wsp-delim)

TESTWSP([custom delimiters (squeeze)],[],
[delim : -ws trimnl],
[semicolon: separated::list: of :words],
[NF: 5
0: semicolon
1: " separated"
2: list
3: " of "
4: words
])

TESTWSP([custom delimiters (no squeeze)],[],
[delim : -ws -squeeze_delims trimnl],
[semicolon: separated::list: of :words],
[NF: 6
0: semicolon
1: " separated"
2: ""
3: list
4: " of "
5: words
])

TESTWSP([custom, with returned delimiters],[],
[delim : -ws trimnl return_delims],
[semicolon: separated::list: of :words],
[NF: 9
0: semicolon
1: :
2: " separated"
3: :
4: list
5: :
6: " of "
7: :
8: words
])

TESTWSP([custom, with returned & squeezed delimiters],[],
[delim : -ws trimnl return_delims -squeeze_delims],
[semicolon: separated::list: of :words],
[NF: 10
0: semicolon
1: :
2: " separated"
3: :
4: :
5: list
6: :
7: " of "
8: :
9: words
])

WSPGROUP(wsp-sed)

TESTWSP([sed expressions],[],[sed],
[arg1 s/foo/bar/g;s/bar baz/quz quux/ arg2],
[NF: 3
0: arg1
1: "s/foo/bar/g;s/bar baz/quz quux/"
2: arg2
])

WSPGROUP()

TESTWSP([C escapes on],[wcp-c-escape],[cescapes],
[a\ttab form\ffeed and new\nline],
[NF: 4
0: a\ttab
1: form\ffeed
2: and
3: new\nline
])

TESTWSP([C escapes off],[wcp-c-escape-off],[-cescapes],
[a\ttab form\ffeed and new\nline],
[NF: 4
0: attab
1: formffeed
2: and
3: newnline
])

TESTWSP([ws elimination],[wsp-ws-elim],[delim ' ()' ws return_delims],
[( list  items  )],
[NF: 4
0: (
1: list
2: items
3: )
])

TESTWSP([ws elimination + return delim],[wsp-ws-elim-ret],
[-default novar nocmd delim ":," return_delims ws dquote],
["foo" : "bar", "quux" : "baaz" ],
[NF: 7
0: foo
1: :
2: bar
3: ,
4: quux
5: :
6: baaz
])

TESTWSP([empty quotes],[wsp-empty-quotes],[delim : ws return_delims],
[t=""],
[NF: 1
0: t=
])

TESTWSP([delimiter following empty quotes],
[],[delim : ws return_delims],
[t="":r],
[NF: 3
0: t=
1: :
2: r
])

TESTWSP([suppress ws trimming within quotes],
[],
[default delim , ws return_delims],
[nocomponent,nonewline, formatfield="In message %{text}, "],
[NF: 5
0: nocomponent
1: ,
2: nonewline
3: ,
4: "formatfield=In message %{text}, "
])

TESTWSP([unescape],
[wsp-unescape wsp-unescape-simple],
[-default novar nocmd quote escape ':+:\\""'],
[\Seen "quote \"" "bs \\"],
[NF: 3
0: \\Seen
1: "quote \""
2: "bs \\"
])

TESTWSP([unescape: word/quote],
[wsp-unescape wsp-unescape-word],
[-default novar nocmd quote escape-word '\\""' escape-quote ':+0x:\\""'],
[\Seen "quote \"" "bs \\" "3\x31 \101" 3\x31 \101],
[NF: 6
0: Seen
1: "quote \""
2: "bs \\"
3: "31 A"
4: 3x31
5: 101
])

TESTWSP([dquote],[],[-default novar nocmd dquote],
[a "quoted example" isn't it],
[NF: 4
0: a
1: "quoted example"
2: isn't
3: it
])

TESTWSP([squote],[],[-default novar nocmd squote],
[a 'quoted example' isn"t it],
[NF: 4
0: a
1: "quoted example"
2: "isn\"t"
3: it
])

WSPGROUP(wsp-incr)

TESTWSP([incremental],[],[incremental],
[incremental "input test" line


],
[NF: 1
0: incremental
NF: 1
0: "input test"
NF: 1
0: line
],
[input exhausted
])

TESTWSP([incremental append],[],[incremental append],
[incremental "input test" line


],
[NF: 1
0: incremental
NF: 2
0: incremental
1: "input test"
NF: 3
0: incremental
1: "input test"
2: line
],
[input exhausted
])

TESTWSP([incremental ws],
[],[return_delims -squeeze_delims incremental ws],
[a   list  test


],
[NF: 1
0: a
NF: 1
0: list
NF: 1
0: test
],
[input exhausted
])


dnl Something that doesn't fit into TESTWSP

AT_SETUP([simple command substitution])
AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-1])
AT_CHECK([
mkdir dir
> dir/file

wsp -nocmd <<'EOT'
begin $(find dir) end
EOT
],
[0],
[NF: 4
0: begin
1: dir
2: dir/file
3: end
])
AT_CLEANUP

AT_SETUP([quoted command substitution])
AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-2])
AT_CHECK([
mkdir dir
> dir/file

wsp -nocmd <<'EOT'
begin "$(find dir)" end
EOT
],
[0],
[NF: 3
0: begin
1: "dir dir/file"
2: end
])
AT_CLEANUP

AT_SETUP([coalesced command substitution])
AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-3])
AT_CHECK([
mkdir dir
> dir/file

wsp -nocmd <<'EOT'
begin($(find dir))end
EOT
],
[0],
[NF: 2
0: begin(dir
1: dir/file)end
])
AT_CLEANUP

AT_SETUP([quoted coalesced command substitution])
AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-4])
AT_CHECK([
mkdir dir
> dir/file

wsp -nocmd <<'EOT'
"begin($(find dir))end"
EOT
],
[0],
[NF: 1
0: "begin(dir dir/file)end"
])
AT_CLEANUP

AT_SETUP([variable and command substitution])
AT_KEYWORDS([wordsplit wsp wsp-var wsp-var24 wsp-cmd wsp-cmd-5])
AT_CHECK([
mkdir dir
> dir/file

DIR=dir wsp -nocmd -novar<<'EOT'
begin $(find $DIR) end
EOT
],
[0],
[NF: 4
0: begin
1: dir
2: dir/file
3: end
])
AT_CLEANUP

AT_SETUP([variable expansion and command substitution in quotes])
AT_KEYWORDS([wordsplit wsp wsp-var wsp-var25 wsp-cmd wsp-cmd-6])
AT_CHECK([
mkdir dir
> dir/file

DIR=dir wsp -nocmd -novar<<'EOT'
"begin($(find $DIR))end"
EOT
],
[0],
[NF: 1
0: "begin(dir dir/file)end"
])
AT_CLEANUP

AT_SETUP([pathname expansion])
AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-1])
AT_CHECK([
mkdir dir
> dir/1.c
> dir/2.c
> dir/3.b

wsp pathexpand<<'EOT'
begin dir/*.c end
EOT
],
[0],
[NF: 4
0: begin
1: dir/1.c
2: dir/2.c
3: end
])
AT_CLEANUP

AT_SETUP([pathname expansion: no match])
AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-2])
AT_CHECK([
mkdir dir
> dir/1.c
> dir/2.b

wsp pathexpand<<'EOT'
begin dir/*.d end
EOT
],
[0],
[NF: 3
0: begin
1: dir/*.d
2: end
])
AT_CLEANUP

AT_SETUP([pathname expansion: nullglob])
AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-3])
AT_CHECK([
mkdir dir
> dir/1.c
> dir/2.b

wsp pathexpand nullglob<<'EOT'
begin dir/*.d end
EOT
],
[0],
[NF: 2
0: begin
1: end
])
AT_CLEANUP

AT_SETUP([pathname expansion: failglob])
AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-4])
AT_CHECK([
mkdir dir
> dir/1.c
> dir/2.b

wsp pathexpand failglob<<'EOT'
begin dir/*.d end
EOT
],
[0],
[],
[no files match pattern dir/*.d
])
AT_CLEANUP

m4_popdef([TESTWSP])
m4_popdef([wspnum])
m4_popdef([wspid])
m4_popdef([genkw])
m4_popdef([wspgroupnum])
m4_popdef([wspgroupname])
m4_popdef([WSPGROUP])
