# file      : tests/builtin/sed.testscript
# license   : MIT; see accompanying LICENSE file

test.arguments = "sed"
test.options += -c

: unknown-option
:
{{
  : unparsed
  :
  $* -u >'option -u' 2>"sed: unknown option '-u'" == 1

  : parsed
  :
  {{
    test.options += -o -u

    : start
    :
    $* -u -n -e 's/a/b/p' <'a' >>EOO
      option -u
      b
      EOO

    : middle
    :
    $* -n -u -e 's/a/b/p' <'a' >>EOO
      option -u
      b
      EOO

    : end
    :
    $* -n -e 's/a/b/p' -u <'a' >>EOO
      option -u
      b
      EOO

    : before-args
    :
    {
      echo 'a' >=f

      $* -n -e 's/a/b/p' -u f >>EOO
        option -u
        b
        EOO
    }
  }}

  : arg
  :
  {
    echo 'a' >=-u

    $* -n -e 's/a/b/p' -- -u >'b'
  }
}}

: arg
:
{{
  : auto-prn
  :
  {{
    $* -n -e 's/fox/bar/' <'foo'        : on
    $*    -e 's/fox/bar/' <'foo' >'foo' : off
  }}

  : script
  :
  {{
    : missed
    :
    $* 2>>EOE != 0
      sed: missing script
      EOE

    : missed-val
    :
    $* -e 2>>EOE != 0
      sed: missing value for option '-e'
      EOE

    : empty
    :
    $* -e '' 2>>EOE != 0
      sed: empty script
      EOE

    : invalid
    :
    $* -e 'z' 2>>EOE != 0
      sed: unknown command in 'z': only 's' command supported
      EOE
  }}

  : file
  :
  {{
    : exist
    :
    {
      cat <'foo' >=f

      $* -e 's/foo/bar/' f >'bar'
    }

    : none
    :
    $* -e 's/foo/bar/' <'foo' >'bar'

    : dash
    :
    $* -e 's/foo/bar/' - <'foo' >'bar'

    : not-exist
    :
    $* -e 's/foo/bar/' f 2>>/~%EOE% != 0
      %sed: unable to edit '.+/f': .+%
      EOE

    : empty
    :
    $* -e 's/foo/bar/' '' 2>>EOE != 0
      sed: invalid path ''
      EOE
  }}

  : unexpected
  :
  $* -e 's/a//' a b 2>>EOE != 0
    sed: unexpected argument 'b'
    EOE
}}

: command
:
{{
  : subst
  :
  {{
    : parsing
    :
    {{
      : delim
      :
      {{
        : none
        :
        $* -e 's' 2>>EOE != 0
          sed: no delimiter for 's' command in 's'
          EOE

        : invalid
        :
        $* -e 's\\' 2>>EOE != 0
          sed: invalid delimiter for 's' command in 's\\'
          EOE
      }}

      : regex
      :
      {{
        : unterminated
        :
        $* -e 's/foo' 2>>EOE != 0
          sed: invalid 's' command 's/foo': no delimiter after regex
          EOE

        : empty
        :
        $* -e 's///' 2>>EOE != 0
          sed: invalid 's' command 's///': empty regex
          EOE

        : invalid
        :
        : Note that old versions of libc++ (for example 1.1) do not detect some
        : regex errors. For example '*' is parsed successfully.
        :
        $* -e 's/foo[/bar/' 2>>~%EOE% != 0
          %sed: invalid regex 'foo\[' in 's/foo\[/bar/'.*%
          EOE
      }}

      : unterminated-replacement
      :
      $* -e 's/foo/bar' 2>>EOE != 0
        sed: invalid 's' command 's/foo/bar': no delimiter after replacement
        EOE

      : invalid-flags
      :
      $* -e 's/foo/bar/a' 2>>EOE != 0
        sed: invalid 's' command flag 'a' in 's/foo/bar/a'
        EOE
    }}

    : exec
    :
    {{
      : flags
      :
      {{
        : global
        :
        {{
          $* -e 's/o/a/g' <'foo' >'faa' : on
          $* -e 's/o/a/'  <'foo' >'fao' : off
        }}

        : icase
        :
        {{
          $* -e 's/O/a/i' <'foo' >'fao' : on
          $* -e 's/O/a/'  <'foo' >'foo' : off
        }}

        : print
        :
        {{
          $* -n -e 's/o/a/p' <'foo' >'fao' : on-match
          $* -n -e 's/o/a/'  <'foo'        : off-match
          $* -n -e 's/u/a/p' <'foo'        : on-no-match
        }}
      }}

      : search
      :
      {{
        : anchor
        :
        {{
          $* -n -e 's/^o/a/gp'  <'oof' >'aof' : begin
          $* -n -e 's/o$/a/gp' <'foo' >'foa' : end
        }}

        : match
        : Match corner cases
        :
        {{
          $* -n -e 's/a/b/p'  <'a'    >'b'    : full
          $* -n -e 's/a/b/p'  <'ac'   >'bc'   : left
          $* -n -e 's/a/b/p'  <'ca'   >'cb'   : right
          $* -n -e 's/a/b/pg' <'xaax' >'xbbx' : adjacent
        }}
      }}

      : replacement
      :
      {{
        : ecma-escape
        :
        {{
          $* <'xay' -e 's/a/$b/'    >'x$by'  : none
          $* <'xay' -e 's/a/$/'     >'x$y'   : none-term
          $* <'xay' -e 's/a/$$/'    >'x$y'   : self
          $* <'xay' -e 's/a/b$&c/'  >'xbacy' : match
          $* <'xay' -e 's/a/b$`c/'  >'xbxcy' : match-precede
          $* <'xay' -e "s/a/b\$'c/" >'xbycy' : match-follow

          : capture
          :
          $* <'abcdefghij' -e 's/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)/$1$10/' >'aj'
        }}

        : perl-escape
        :
        {{
          $* <'xay' -e 's/a/\b/'  >'xby' : none
          $* <'xay' -e 's/a/\/'   >'xy'  : none-term
          $* <'xay' -e 's/a/\\/' >'x\y'  : self

          : capture
          :
          $* <'abcdefghij' -e 's/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)/\1\10/' >'aa0'

          : upper
          :
          {{
            $* <'xay' -e 's/a/\U/'        >'xy'   : none
            $* <'xay' -e 's/a/\Uvz/'      >'xVZy' : repl
            $* <'xay' -e 's/a/\Uv\Ez/'    >'xVzy' : end
            $* <'aa'  -e 's/a/v\Uz/g'     >'vZvZ' : locality
            $* <'xay' -e 's/(a)/\U\1/'    >'xAy'  : capt
            $* <'x-y' -e 's/(a?)-/\U\1z/' >'xZy'  : capt-empty
            $* <'xay' -e 's/a/\uvz/'      >'xVzy' : once
          }}

          : lower
          :
          {{
            $* <'xay' -e 's/a/\lVZ/' >'xvZy' : once
          }}
        }}
      }}

      $* -e 's/a//' <:'b' >'b' : no-newline
      $* -e 's/a//' <:''       : empty-stdin

      : empty-file
      :
      {
        touch f

        $* -e 's/a//' f
      }
    }}
  }}

  : multiple
  :
  {{
    $* -e 's/b/x/' -e 's/x/y/' -e 's/c/z/' <'abc' >'ayz' : replace-replacement

    : new-cycle
    :
    $* -e 's/b/x/p' -e 's/x/y/p' <<EOI >>EOO
      abc
      klm
      dxe
      EOI
      axc
      klm
      dye
      EOO

    : quiet
    :
    $* -n -e 's/b/x/p' -e 's/x/y/p' <<EOI >>EOO
      abc
      klm
      dxe
      EOI
      axc
      dye
      EOO
  }}
}}

: in-place
:
{{
  : no-file
  :
  $* -i -e 's/a/b/' 2>>EOE != 0
    sed: -i|--in-place option specified while reading from stdin
    EOE

  : edit
  :
  {
    cat <'foo' >=f

    $* -i -e 's/foo/bar/' f

    cat f >'bar'
  }
}}

: big
:
: Sed a big file (about 100K) to test that the builtin is asynchronous.
:
{
  s="--------------------------------"
  s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
  s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
  s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
  cat <"$s" | $* -e 's/^x//' | cat >"$s"
}

: deep-recursion
:
: Test that sed doesn't crash on a potentially deep recursion (the file size
: is about 4K), which may occur for the recursive implementations of regex
: (GCC, etc).
:
{
  s="--------------------------------"
  s="$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"
  s="$s$s$s$s$s$s$s$s"
  cat <"$s" | $* -e 's/-*/x/' | cat >x
}
