# file      : tests/test/script/runner/set.testscript
# license   : MIT; see accompanying LICENSE file

.include ../common.testscript

: special
:
{
  : pipelining
  :
  $c <'set foo | cat >bar' && $b 2>>EOE != 0
  testscript:1:1: error: set builtin must be the last pipe command
    info: test id: 1
  EOE

  : redirecting
  :
  {
    : stdout
    :
    $c <'set foo >bar' && $b 2>>EOE != 0
    testscript:1:1: error: set builtin stdout cannot be redirected
      info: test id: 1
    EOE

    : stderr
    :
    $c <'set foo 2>bar' && $b 2>>EOE != 0
    testscript:1:1: error: set builtin stderr cannot be redirected
      info: test id: 1
    EOE
  }

  : status
  :
  $c <'set foo == 1' && $b 2>>EOE != 0
  testscript:1:1: error: set builtin exit code cannot be checked
    info: test id: 1
  EOE
}

: options
:
{
  : unknown
  :
  $c <'set -u' && $b 2>>EOE != 0
  testscript:1:1: error: set: unknown option '-u'
    info: test id: 1
  EOE

  : both-newline-whitespace
  :
  $c <'set -nw' && $b 2>>EOE != 0
  testscript:1:1: error: set: both -n|--newline and -w|--whitespace specified
    info: test id: 1
  EOE
}

: arguments
:
{
  : none
  :
  $c <'set -e' && $b 2>>EOE != 0
  testscript:1:1: error: set: missing variable name
    info: test id: 1
  EOE

  : unexpected
  :
  $c <'set foo bar baz' && $b 2>>EOE != 0
  testscript:1:1: error: set: unexpected argument 'baz'
    info: test id: 1
  EOE

  : empty-attrs
  :
  $c <"set baz ''" && $b 2>>EOE != 0
  testscript:1:1: error: set: empty variable attributes
    info: test id: 1
  EOE

  : empty-var
  :
  $c <"set ''" && $b 2>>EOE != 0
  testscript:1:1: error: set: empty variable name
    info: test id: 1
  EOE
}

: whitespace-separated-list
:
{
  : non-exact
  :
  {
    : non-empty
    :
    $c <<EOI && $b
    set -w baz <' foo   bar ';
    echo $regex.apply($baz, '^(.*)$', '"\1"') >'"foo" "bar"'
    EOI

    : empty
    :
    $c <<EOI && $b
    set -w baz <:'';
    echo $regex.apply($baz, '^(.*)$', '"\1"') >''
    EOI

    : spaces
    :
    $c <<EOI && $b
    set -w baz <'  ';
    echo $regex.apply($baz, '^(.*)$', '"\1"') >''
    EOI
  }

  : exact
  :
  {
    : trailing-ws
    :
    $c <<EOI && $b
    set --exact --whitespace baz <' foo   bar ';
    echo $regex.apply($baz, '^(.*)$', '"\1"') >'"foo" "bar" ""'
    EOI

    : no-trailing-ws
    :
    : Note that we need to strip the default trailing newline as well with the
    : ':' modifier.
    :
    $c <<EOI && $b
    set -e -w baz <:' foo bar';
    echo $regex.apply($baz, '^(.*)$', '"\1"') >'"foo" "bar"'
    EOI

    : empty
    :
    $c <<EOI && $b
    set -e -w baz <:'';
    echo $regex.apply($baz, '^(.*)$', '"\1"') >''
    EOI

    : spaces
    :
    $c <<EOI && $b
    set -e -w baz <'  ';
    echo $regex.apply($baz, '^(.*)$', '"\1"') >'""'
    EOI
  }
}

: newline-separated-list
:
{
  : non-exact
  :
  $c <<EOI && $b
  set -n baz <<EOF;

  foo

  bar

  EOF
  echo $regex.apply($baz, '^(.*)$', '"\1"') >'"" "foo" "" "bar" ""'
  EOI

  : exact
  :
  {
    : trailing-newline
    :
    $c <<EOI && $b
    set --exact --newline baz <<EOF;

    foo

    bar

    EOF
    echo $regex.apply($baz, '^(.*)$', '"\1"') >'"" "foo" "" "bar" "" ""'
    EOI

    : no-trailing-newline
    :
    $c <<EOI && $b
    set --exact --newline baz <<:EOF;

    foo

    bar
    EOF
    echo $regex.apply($baz, '^(.*)$', '"\1"') >'"" "foo" "" "bar"'
    EOI
  }
}

: string
:
{
  : non-exact
  :
  $c <<EOI && $b
  set baz <<EOF;

  foo

  bar

  EOF
  echo ($baz[0]) >>EOO

  foo

  bar

  EOO
  EOI

  : roundtrip
  :
  echo 'foo' | set bar;
  echo "$bar" >'foo'

  : exact
  :
  : Note that echo adds the trailing newline, so EOF and EOO here-documents
  : differ by this newline.
  :
  {
    : trailing-newline
    :
    $c <<EOI && $b
    set -e baz <<EOF;

    foo

    bar
    EOF
    echo ($baz[0]) >>EOO

    foo

    bar

    EOO
    EOI

    : no-trailing-newline
    :
    $c <<EOI && $b
    set -e baz <<:EOF;

    foo

    bar
    EOF
    echo ($baz[0]) >>EOO

    foo

    bar
    EOO
    EOI
  }
}

: special-vars
:
{
  $c <<EOI && $b
    set -w test.options <'-o foo';
    $* >'foo'
    EOI
}

: deadline
:
{
  : not-reached
  :
  $c <<EOI && $b
  env -t 10 -- $* -o 'foo' | set bar;
  echo "$bar" >'foo'
  EOI

  : non-pipe
  :
  $c <<EOI && $b
  env -t 10 -- set bar <'foo';
  echo "$bar" >'foo'
  EOI

  : set-reached
  :
  $c <<EOI && $b 2>>~%EOE% != 0
  $* -o 'foo' -l 10 | env -t 1 -- set bar
  EOI
  %testscript:.*: error: .+driver.* terminated: execution timeout expired%
  %.
  EOE

  : driver-reached
  :
  $c <<EOI && $b 2>>~%EOE% != 0
  env -t 1 -- $* -o 'foo' -l 10 | set bar
  EOI
  %testscript:.*: error: .+driver.* terminated: execution timeout expired%
  %.
  EOE

  : read-some-data
  :
  {
    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$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s"

    : failure
    :
    $c <<EOI && $b 2>>~%EOE% != 0
    echo "$s" >=f;
    $* -o 'foo' -l 10 | cat f - | env -t 2 -- set bar
    EOI
    %testscript:.*: error: process .+driver.* terminated: execution timeout expired%
    %.
    %testscript:.*: error: builtin cat terminated: execution timeout expired%
    %.
    EOE

    : success
    :
    $c <<EOI && $b
    echo "$s" >=f;
    timeout --success 2;

    # Suppress cat's 'broken pipe' diagnostics.
    #
    $* -o 'foo' -l 10 | cat f - 2>- | set bar
    EOI
  }

  : split
  :
  : Test various splitting modes as above, but now reading the stream in the
  : non-blocking mode.
  :
  {
    : whitespace-separated-list
    :
    {
      : non-exact
      :
      {
        : non-empty
        :
        $c <<EOI && $b
        timeout 10;
        set -w baz <' foo   bar ';
        echo $regex.apply($baz, '^(.*)$', '"\1"') >'"foo" "bar"'
        EOI

        : empty
        :
        $c <<EOI && $b
        timeout 10;
        set -w baz <:'';
        echo $regex.apply($baz, '^(.*)$', '"\1"') >''
        EOI

        : spaces
        :
        $c <<EOI && $b
        timeout 10;
        set -w baz <'  ';
        echo $regex.apply($baz, '^(.*)$', '"\1"') >''
        EOI
      }

      : exact
      :
      {
        : trailing-ws
        :
        $c <<EOI && $b
        timeout 10;
        set --exact --whitespace baz <' foo   bar ';
        echo $regex.apply($baz, '^(.*)$', '"\1"') >'"foo" "bar" ""'
        EOI

        : no-trailing-ws
        :
        : Note that we need to strip the default trailing newline as well with the
        : ':' modifier.
        :
        $c <<EOI && $b
        timeout 10;
        set -e -w baz <:' foo bar';
        echo $regex.apply($baz, '^(.*)$', '"\1"') >'"foo" "bar"'
        EOI

        : empty
        :
        $c <<EOI && $b
        timeout 10;
        set -e -w baz <:'';
        echo $regex.apply($baz, '^(.*)$', '"\1"') >''
        EOI

        : spaces
        :
        $c <<EOI && $b
        timeout 10;
        set -e -w baz <'  ';
        echo $regex.apply($baz, '^(.*)$', '"\1"') >'""'
        EOI
      }
    }

    : newline-separated-list
    :
    {
      : non-exact
      :
      $c <<EOI && $b
      timeout 10;
      set -n baz <<EOF;

      foo

      bar

      EOF
      echo $regex.apply($baz, '^(.*)$', '"\1"') >'"" "foo" "" "bar" ""'
      EOI

      : exact
      :
      {
        : trailing-newline
        :
        $c <<EOI && $b
        timeout 10;
        set --exact --newline baz <<EOF;

        foo

        bar

        EOF
        echo $regex.apply($baz, '^(.*)$', '"\1"') >'"" "foo" "" "bar" "" ""'
        EOI

        : no-trailing-newline
        :
        $c <<EOI && $b
        timeout 10;
        set --exact --newline baz <<:EOF;

        foo

        bar
        EOF
        echo $regex.apply($baz, '^(.*)$', '"\1"') >'"" "foo" "" "bar"'
        EOI
      }
    }

    : string
    :
    {
      : non-exact
      :
      $c <<EOI && $b
      timeout 10;
      set baz <<EOF;

      foo

      bar

      EOF
      echo ($baz[0]) >>EOO

      foo

      bar

      EOO
      EOI

      : exact
      :
      : Note that echo adds the trailing newline, so EOF and EOO here-documents
      : differ by this newline.
      :
      {
        : trailing-newline
        :
        $c <<EOI && $b
        timeout 10;
        set -e baz <<EOF;

        foo

        bar
        EOF
        echo ($baz[0]) >>EOO

        foo

        bar

        EOO
        EOI

        : no-trailing-newline
        :
        $c <<EOI && $b
        timeout 10;
        set -e baz <<:EOF;

        foo

        bar
        EOF
        echo ($baz[0]) >>EOO

        foo

        bar
        EOO
        EOI
      }
    }
  }
}

: attributes
:
{
  : dir_path
  :
  $c <<EOI && $b
  set bar [dir_path] <'foo';
  echo $bar >/'foo/'
  EOI

  : null
  :
  $c <<EOI && $b
  set foo [null] <-;
  echo $foo >''
  EOI

  : none
  :
  $c <<EOI && $b 2>>EOE != 0
  set -w baz <'foo bar';
  echo "$baz"
  EOI
  testscript:2:8: error: concatenating variable expansion contains multiple values
  EOE

  # @@ Move the following tests to build2 parser unit tests when created.
  #
  : empty-brackets
  :
  $c <<EOI && $b 2>>EOE != 0
  set -w baz '[]' <'foo bar';
  echo "$baz"
  EOI
  testscript:2:8: error: concatenating variable expansion contains multiple values
  EOE

  : no-left-bracket
  :
  $c <<EOI && $b 2>>EOE != 0
  set -w baz x
  EOI
  <attributes>:1:1: error: expected '[' instead of 'x'
    testscript:1:1: info: while parsing attributes 'x'
    info: test id: 1
  EOE

  : unknown
  :
  $c <<EOI && $b 2>>EOE != 0
  set -w baz [x]
  EOI
  <attributes>:1:1: error: unknown value attribute x
    testscript:1:1: info: while parsing attributes '[x]'
    info: test id: 1
  EOE

  : junk
  :
  $c <<EOI && $b 2>>EOE != 0
  set -w baz '[string] x'
  EOI
  <attributes>:1:10: error: trailing junk after ']'
    testscript:1:1: info: while parsing attributes '[string] x'
    info: test id: 1
  EOE
}