# file      : tests/test/script/builtin/sed.testscript
# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license   : MIT; see accompanying LICENSE file

.include ../common.testscript

: arg
:
{
  : auto-prn
  :
  {
    $c <"sed -n -e 's/fox/bar/' <'foo'       " && $b : on
    $c <"sed    -e 's/fox/bar/' <'foo' >'foo'" && $b : off
  }

  : script
  :
  {
    : missed
    :
    $c <'sed' && $b 2>>/EOE != 0
    testscript:1:1: error: sed exit code 1 != 0
      info: stderr: test/1/stderr
    sed: missing script
      info: test id: 1
    EOE

    : missed-val
    :
    $c <'sed -e' && $b 2>>/EOE != 0
    testscript:1:1: error: sed exit code 1 != 0
      info: stderr: test/1/stderr
    sed: missing script
      info: test id: 1
    EOE

    : empty
    :
    $c <"sed -e ''" && $b 2>>/EOE != 0
    testscript:1:1: error: sed exit code 1 != 0
      info: stderr: test/1/stderr
    sed: empty script
      info: test id: 1
    EOE

    : multiple
    :
    $c <"sed -e 's/a//' -e 's/a//'" && $b 2>>/EOE != 0
    testscript:1:1: error: sed exit code 1 != 0
      info: stderr: test/1/stderr
    sed: multiple scripts
      info: test id: 1
    EOE

    : invalid
    :
    $c <"sed -e 'z'" && $b 2>>/EOE != 0
    testscript:1:1: error: sed exit code 1 != 0
      info: stderr: test/1/stderr
    sed: only 's' command supported
      info: test id: 1
    EOE
  }

  : file
  :
  {
    : exist
    :
    $c <<EOI && $b
    cat <'foo' >=f;
    sed -e 's/foo/bar/' f >'bar'
    EOI

    : none
    :
    $c <<EOI && $b
    sed -e 's/foo/bar/' <'foo' >'bar'
    EOI

    : dash
    :
    $c <<EOI && $b
    sed -e 's/foo/bar/' - <'foo' >'bar'
    EOI

    : not-exist
    :
    $c <"sed -e 's/foo/bar/' f" && $b 2>>/~%EOE% != 0
    testscript:1:1: error: sed exit code 1 != 0
      info: stderr: test/1/stderr
    %sed: unable to edit '.+/1/f': .+%
      info: test id: 1
    EOE

    : empty
    :
    $c <"sed -e 's/foo/bar/' ''" && $b 2>>/EOE != 0
    testscript:1:1: error: sed exit code 1 != 0
      info: stderr: test/1/stderr
    sed: invalid path ''
      info: test id: 1
    EOE
  }

  : unexpected
  :
  $c <"sed -e 's/a//' a b" && $b 2>>/EOE != 0
  testscript:1:1: error: sed exit code 1 != 0
    info: stderr: test/1/stderr
  sed: unexpected argument 'b'
    info: test id: 1
  EOE
}

: command
:
{
  : subst
  :
  {
    : parsing
    :
    {
      : delim
      :
      {
        : none
        :
        $c <"sed -e 's'" && $b 2>>/EOE != 0
        testscript:1:1: error: sed exit code 1 != 0
          info: stderr: test/1/stderr
        sed: no delimiter for 's' command
          info: test id: 1
        EOE

        : invalid
        :
        $c <"sed -e 's\\'" && $b 2>>/EOE != 0
        testscript:1:1: error: sed exit code 1 != 0
          info: stderr: test/1/stderr
        sed: invalid delimiter for 's' command
          info: test id: 1
        EOE
      }

      : regex
      :
      {
        : unterminated
        :
        $c <"sed -e 's/foo'" && $b 2>>/EOE != 0
        testscript:1:1: error: sed exit code 1 != 0
          info: stderr: test/1/stderr
        sed: unterminated 's' command regex
          info: test id: 1
        EOE

        : empty
        :
        $c <"sed -e 's///'" && $b 2>>/EOE != 0
        testscript:1:1: error: sed exit code 1 != 0
          info: stderr: test/1/stderr
        sed: empty regex in 's' command
          info: test id: 1
        EOE

        : invalid
        :
        : Note that old versions of libc++ (for example 1.1) do not detect some
        : regex errors. For example '*' is parsed successfully.
        :
        $c <"sed -e 's/foo[/bar/'" && $b 2>>/~%EOE% != 0
        testscript:1:1: error: sed exit code 1 != 0
          info: stderr: test/1/stderr
        %sed: invalid regex.*%
          info: test id: 1
        EOE
      }

      : unterminated-replacement
      :
      $c <"sed -e 's/foo/bar'" && $b 2>>/EOE != 0
      testscript:1:1: error: sed exit code 1 != 0
        info: stderr: test/1/stderr
      sed: unterminated 's' command replacement
        info: test id: 1
      EOE

      : invalid-flags
      :
      $c <"sed -e 's/foo/bar/a'" && $b 2>>/EOE != 0
      testscript:1:1: error: sed exit code 1 != 0
        info: stderr: test/1/stderr
      sed: invalid 's' command flag 'a'
        info: test id: 1
      EOE
    }

    : exec
    :
    {
      : flags
      :
      {
        : global
        :
        {
          $c <"sed -e 's/o/a/g' <'foo' >'faa'" && $b : on
          $c <"sed -e 's/o/a/'  <'foo' >'fao'" && $b : off
        }

        : icase
        :
        {
          $c <"sed -e 's/O/a/i' <'foo' >'fao'" && $b : on
          $c <"sed -e 's/O/a/'  <'foo' >'foo'" && $b : off
        }

        : print
        :
        {
          $c <"sed -n -e 's/o/a/p' <'foo' >'fao'" && $b : on-match
          $c <"sed -n -e 's/o/a/'  <'foo'       " && $b : off-match
          $c <"sed -n -e 's/u/a/p' <'foo'       " && $b : on-no-match
        }
      }

      : search
      {
        : anchor
        :
        {
          $c <"sed -n -e 's/^o/a/gp'  <'oof' >'aof'" && $b : begin
          $c <"sed -n -e 's/o\$/a/gp' <'foo' >'foa'" && $b : end
        }

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

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

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

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

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

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

          : lower
          :
          {
            $c <"sed <'xay' -e 's/a/\\lVZ/' >'xvZy'" && $b : once
          }
        }
      }

      $c <"sed -e 's/a//' <:'b' >'b'" && $b : no-newline
      $c <"sed -e 's/a//' <:''      " && $b : empty-stdin

      : empty-file
      :
      $c <<EOI && $b
      touch f;
      sed -e 's/a//' f
      EOI
    }
  }
}

: in-place
:
{
  : no-file
  :
  $c <"sed -i -e 's/a/b/'" && $b 2>>/EOE != 0
  testscript:1:1: error: sed exit code 1 != 0
    info: stderr: test/1/stderr
  sed: -i option specified while reading from stdin
    info: test id: 1
  EOE

  : edit
  :
  $c <<EOI && $b
  cat <'foo' >=f;
  sed -i -e 's/foo/bar/' f;
  cat f >'bar'
  EOI
}

: big
:
: Sed a big file (about 100K) to test that the builtin is asynchronous.
:
{
  $c <<EOI && $b
  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" | sed -e 's/^x//' | cat >"$s"
  EOI
}