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

.include ../common.testscript

: short-circuit
:
: Test expression result calculation and short-circuiting. We verify the
: correctness of the above for all possible expressions of a length up to 3
: operands. While some of tests may look redundant the full expression tree is
: easier to maintain than the one with gaps (also much less chances that we
: have missed something useful). Each pipe-operand has a label which is printed
: to stdout when the pipe is executed. Pipes stdouts are pass-redirected, so we
: just check that build2 output matches expectations.
:
: Note that expression evaluation goes left-to-right with AND and OR having the
: same precedence.
:
{{
  true  = '$* >| -o'
  false = '$* -s 1 >| -o'

  bf = [cmdline] $b 2>-

  : true
  :
  {{
    : TERM
    :
    $c <<"EOI" && $b >>EOO
    $true 1
    EOI
    1
    EOO

    : OR
    :
    {{
      : true
      :
      {{
        : TERM
        :
        $c <<"EOI" && $b >>EOO
        $true 1 || $true 2
        EOI
        1
        EOO

        : OR
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $true 1 || $true 2 || $true 3
            EOI
            1
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $b >>EOO
            $true 1 || $true 2 || $false 3
            EOI
            1
            EOO
          }
        }}

        : AND
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $true 1 || $true 2 && $true 3
            EOI
            1
            3
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $true 1 || $true 2 && $false 3
            EOI
            1
            3
            EOO
          }
        }}
      }}

      : false
      :
      {{
        : TERM
        :
        $c <<"EOI" && $b >>EOO
        $true 1 || $false 2
        EOI
        1
        EOO

        : OR
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $true 1 || $false 2 || $true 3
            EOI
            1
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $b >>EOO
            $true 1 || $false 2 || $false 3
            EOI
            1
            EOO
          }
        }}

        : AND
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $true 1 || $false 2 && $true 3
            EOI
            1
            3
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $true 1 || $false 2 && $false 3
            EOI
            1
            3
            EOO
          }
        }}
      }}
    }}

    : AND
    :
    {{
      : true
      :
      {{
        : TERM
        :
        $c <<"EOI" && $b >>EOO
        $true 1 && $true 2
        EOI
        1
        2
        EOO

        : OR
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $true 1 && $true 2 || $true 3
            EOI
            1
            2
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $b >>EOO
            $true 1 && $true 2 || $false 3
            EOI
            1
            2
            EOO
          }
        }}

        : AND
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $true 1 && $true 2 && $true 3
            EOI
            1
            2
            3
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $true 1 && $true 2 && $false 3
            EOI
            1
            2
            3
            EOO
          }
        }}
      }}

      : false
      :
      {{
        : TERM
        :
        $c <<"EOI" && $bf >>EOO != 0
        $true 1 && $false 2
        EOI
        1
        2
        EOO

        : OR
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $true 1 && $false 2 || $true 3
            EOI
            1
            2
            3
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $true 1 && $false 2 || $false 3
            EOI
            1
            2
            3
            EOO
          }
        }}

        : AND
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $true 1 && $false 2 && $true 3
            EOI
            1
            2
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $true 1 && $false 2 && $false 3
            EOI
            1
            2
            EOO
          }
        }}
      }}
    }}
  }}

  : false
  :
  {{
    : TERM
    :
    $c <<"EOI" && $bf >>EOO != 0
    $false 1
    EOI
    1
    EOO

    : OR
    :
    {{
      : true
      :
      {{
        : TERM
        :
        $c <<"EOI" && $b >>EOO
        $false 1 || $true 2
        EOI
        1
        2
        EOO

        : OR
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $false 1 || $true 2 || $true 3
            EOI
            1
            2
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $b >>EOO
            $false 1 || $true 2 || $false 3
            EOI
            1
            2
            EOO
          }
        }}

        : AND
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $false 1 || $true 2 && $true 3
            EOI
            1
            2
            3
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $false 1 || $true 2 && $false 3
            EOI
            1
            2
            3
            EOO
          }
        }}
      }}

      : false
      :
      {{
        : TERM
        :
        $c <<"EOI" && $bf >>EOO != 0
        $false 1 || $false 2
        EOI
        1
        2
        EOO

        : OR
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $false 1 || $false 2 || $true 3
            EOI
            1
            2
            3
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $false 1 || $false 2 || $false 3
            EOI
            1
            2
            3
            EOO
          }
        }}

        : AND
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $false 1 || $false 2 && $true 3
            EOI
            1
            2
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $false 1 || $false 2 && $false 3
            EOI
            1
            2
            EOO
          }
        }}
      }}
    }}

    : AND
    :
    {{
      : true
      :
      {{
        : TERM
        :
        $c <<"EOI" && $bf >>EOO != 0
        $false 1 && $true 2
        EOI
        1
        EOO

        : OR
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $false 1 && $true 2 || $true 3
            EOI
            1
            3
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $false 1 && $true 2 || $false 3
            EOI
            1
            3
            EOO
          }
        }}

        : AND
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $false 1 && $true 2 && $true 3
            EOI
            1
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $false 1 && $true 2 && $false 3
            EOI
            1
            EOO
          }
        }}
      }}

      : false
      :
      {{
        : TERM
        :
        $c <<"EOI" && $bf >>EOO != 0
        $false 1 && $false 2
        EOI
        1
        EOO

        : OR
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $b >>EOO
            $false 1 && $false 2 || $true 3
            EOI
            1
            3
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $false 1 && $false 2 || $false 3
            EOI
            1
            3
            EOO
          }
        }}

        : AND
        :
        {{
          : true
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $false 1 && $false 2 && $true 3
            EOI
            1
            EOO
          }

          : false
          :
          {
            $c <<"EOI" && $bf >>EOO != 0
            $false 1 && $false 2 && $false 3
            EOI
            1
            EOO
          }
        }}
      }}
    }}
  }}
}}

: diagnostics
:
: Check that the diagnostics is printed for only the last faulty pipe.
:
{{
  true  = '$*'
  false = '$* -s 1 2>'X' -e' # Compares stderr to value that never matches.

  : trailing
  :
  $c <<"EOI" && $b 2>>~/EOE/ != 0
  $false 1 != 0 || $true && $false 2 != 0
  EOI
  /.{7}
  -X
  +2
    info: test id: 1
  EOE

  : non-trailing
  :
  $c <<"EOI" && $b 2>>~/EOE/ != 0
  $false 1 != 0 || $true && $false 2 != 0 && $true
  EOI
  /.{7}
  -X
  +2
    info: test id: 1
  EOE
}}

: escape-builtin
:
if ($cxx.target.class == 'linux')
{
  $c <<EOI && $b
    cat <<EOF >=f;
      x


      y
      EOF

    ^cat --squeeze-blank f >>EOO
      x

      y
      EOO
    EOI
}

: syntax-1
:
{{
  b = [cmdline] $regex.apply($b, '(.+testscript.syntax).+', "\1 = 1'")

  : short-circuit
  :
  : Test expression result calculation and short-circuiting. We verify the
  : correctness of the above for all possible expressions of a length up to 3
  : operands. While some of tests may look redundant the full expression tree is
  : easier to maintain than the one with gaps (also much less chances that we
  : have missed something useful). Each pipe-operand has a label which is printed
  : to stdout when the pipe is executed. Pipes stdouts are pass-redirected, so we
  : just check that build2 output matches expectations.
  :
  : Note that expression evaluation goes left-to-right with AND and OR having the
  : same precedence.
  :
  {{
    true  = '$* >| -o'
    false = '$* -s 1 >| -o'

    bf = [cmdline] $b 2>-

    : true
    :
    {{
      : TERM
      :
      $c <"$true 1" && $b >>EOO
      1
      EOO

      : OR
      :
      {{
        : true
        :
        {{
          : TERM
          :
          $c <"$true 1 || $true 2" && $b >>EOO
          1
          EOO

          : OR
          :
          {{
            : true
            :
            {
              $c <"$true 1 || $true 2 || $true 3" && $b >>EOO
              1
              EOO
            }

            : false
            :
            {
              $c <"$true 1 || $true 2 || $false 3" && $b >>EOO
              1
              EOO
            }
          }}

          : AND
          :
          {{
            : true
            :
            {
              $c <"$true 1 || $true 2 && $true 3" && $b >>EOO
              1
              3
              EOO
            }

            : false
            :
            {
              $c <"$true 1 || $true 2 && $false 3" && $bf >>EOO != 0
              1
              3
              EOO
            }
          }}
        }}

        : false
        :
        {{
          : TERM
          :
          $c <"$true 1 || $false 2" && $b >>EOO
          1
          EOO

          : OR
          :
          {{
            : true
            :
            {
              $c <"$true 1 || $false 2 || $true 3" && $b >>EOO
              1
              EOO
            }

            : false
            :
            {
              $c <"$true 1 || $false 2 || $false 3" && $b >>EOO
              1
              EOO
            }
          }}

          : AND
          :
          {{
            : true
            :
            {
              $c <"$true 1 || $false 2 && $true 3" && $b >>EOO
              1
              3
              EOO
            }

            : false
            :
            {
              $c <"$true 1 || $false 2 && $false 3" && $bf >>EOO != 0
              1
              3
              EOO
            }
          }}
        }}
      }}

      : AND
      :
      {{
        : true
        :
        {{
          : TERM
          :
          $c <"$true 1 && $true 2" && $b >>EOO
          1
          2
          EOO

          : OR
          :
          {{
            : true
            :
            {
              $c <"$true 1 && $true 2 || $true 3" && $b >>EOO
              1
              2
              EOO
            }

            : false
            :
            {
              $c <"$true 1 && $true 2 || $false 3" && $b >>EOO
              1
              2
              EOO
            }
          }}

          : AND
          :
          {{
            : true
            :
            {
              $c <"$true 1 && $true 2 && $true 3" && $b >>EOO
              1
              2
              3
              EOO
            }

            : false
            :
            {
              $c <"$true 1 && $true 2 && $false 3" && $bf >>EOO != 0
              1
              2
              3
              EOO
            }
          }}
        }}

        : false
        :
        {{
          : TERM
          :
          $c <"$true 1 && $false 2" && $bf >>EOO != 0
          1
          2
          EOO

          : OR
          :
          {{
            : true
            :
            {
              $c <"$true 1 && $false 2 || $true 3" && $b >>EOO
              1
              2
              3
              EOO
            }

            : false
            :
            {
              $c <"$true 1 && $false 2 || $false 3" && $bf >>EOO != 0
              1
              2
              3
              EOO
            }
          }}

          : AND
          :
          {{
            : true
            :
            {
              $c <"$true 1 && $false 2 && $true 3" && $bf >>EOO != 0
              1
              2
              EOO
            }

            : false
            :
            {
              $c <"$true 1 && $false 2 && $false 3" && $bf >>EOO != 0
              1
              2
              EOO
            }
          }}
        }}
      }}
    }}

    : false
    :
    {{
      : TERM
      :
      $c <"$false 1" && $bf >>EOO != 0
      1
      EOO

      : OR
      :
      {{
        : true
        :
        {{
          : TERM
          :
          $c <"$false 1 || $true 2" && $b >>EOO
          1
          2
          EOO

          : OR
          :
          {{
            : true
            :
            {
              $c <"$false 1 || $true 2 || $true 3" && $b >>EOO
              1
              2
              EOO
            }

            : false
            :
            {
              $c <"$false 1 || $true 2 || $false 3" && $b >>EOO
              1
              2
              EOO
            }
          }}

          : AND
          :
          {{
            : true
            :
            {
              $c <"$false 1 || $true 2 && $true 3" && $b >>EOO
              1
              2
              3
              EOO
            }

            : false
            :
            {
              $c <"$false 1 || $true 2 && $false 3" && $bf >>EOO != 0
              1
              2
              3
              EOO
            }
          }}
        }}

        : false
        :
        {{
          : TERM
          :
          $c <"$false 1 || $false 2" && $bf >>EOO != 0
          1
          2
          EOO

          : OR
          :
          {{
            : true
            :
            {
              $c <"$false 1 || $false 2 || $true 3" && $b >>EOO
              1
              2
              3
              EOO
            }

            : false
            :
            {
              $c <"$false 1 || $false 2 || $false 3" && $bf >>EOO != 0
              1
              2
              3
              EOO
            }
          }}

          : AND
          :
          {{
            : true
            :
            {
              $c <"$false 1 || $false 2 && $true 3" && $bf >>EOO != 0
              1
              2
              EOO
            }

            : false
            :
            {
              $c <"$false 1 || $false 2 && $false 3" && $bf >>EOO != 0
              1
              2
              EOO
            }
          }}
        }}
      }}

      : AND
      :
      {{
        : true
        :
        {{
          : TERM
          :
          $c <"$false 1 && $true 2" && $bf >>EOO != 0
          1
          EOO

          : OR
          :
          {{
            : true
            :
            {
              $c <"$false 1 && $true 2 || $true 3" && $b >>EOO
              1
              3
              EOO
            }

            : false
            :
            {
              $c <"$false 1 && $true 2 || $false 3" && $bf >>EOO != 0
              1
              3
              EOO
            }
          }}

          : AND
          :
          {{
            : true
            :
            {
              $c <"$false 1 && $true 2 && $true 3" && $bf >>EOO != 0
              1
              EOO
            }

            : false
            :
            {
              $c <"$false 1 && $true 2 && $false 3" && $bf >>EOO != 0
              1
              EOO
            }
          }}
        }}

        : false
        :
        {{
          : TERM
          :
          $c <"$false 1 && $false 2" && $bf >>EOO != 0
          1
          EOO

          : OR
          :
          {{
            : true
            :
            {
              $c <"$false 1 && $false 2 || $true 3" && $b >>EOO
              1
              3
              EOO
            }

            : false
            :
            {
              $c <"$false 1 && $false 2 || $false 3" && $bf >>EOO != 0
              1
              3
              EOO
            }
          }}

          : AND
          :
          {{
            : true
            :
            {
              $c <"$false 1 && $false 2 && $true 3" && $bf >>EOO != 0
              1
              EOO
            }

            : false
            :
            {
              $c <"$false 1 && $false 2 && $false 3" && $bf >>EOO != 0
              1
              EOO
            }
          }}
        }}
      }}
    }}
  }}

  : diagnostics
  :
  : Check that the diagnostics is printed for only the last faulty pipe.
  :
  {{
    true  = '$*'
    false = '$* -s 1 2>'X' -e' # Compares stderr to value that never matches.

    : trailing
    :
    $c <"$false 1 != 0 || $true && $false 2 != 0" && $b 2>>~/EOE/ != 0
    /.{7}
    -X
    +2
      info: test id: 1
    EOE

    : non-trailing
    :
    $c <"$false 1 != 0 || $true && $false 2 != 0 && $true" && $b 2>>~/EOE/ != 0
    /.{7}
    -X
    +2
      info: test id: 1
    EOE
  }}

  : escape-builtin
  :
  if ($cxx.target.class == 'linux')
  {
    $c <<EOI && $b
      cat <<EOF >=f;
        x


        y
        EOF

      ^cat --squeeze-blank f >>EOO
        x

        y
        EOO
      EOI
  }
}}
