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

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

: unknown-option
:
$* -u >'option -u' 2>"cp: unknown option '-u'" == 1

: args
:
{
  : none
  :
  $* 2>"cp: missing arguments" == 1

  : no-source
  :
  $* -R a 2>"cp: missing source path" == 1

  : no-trailing-sep
  :
  $* a b c 2>"cp: multiple source paths without trailing separator for destination directory" == 1

  : empty
  :
  {
    : dest
    :
    $* '' 2>"cp: invalid path ''" == 1

    : src1
    :
    $* '' a 2>"cp: invalid path ''" == 1

    : src2
    :
    $* '' a b/ 2>"cp: invalid path ''" == 1
  }
}

: file
:
: Test synopsis 1: make a file copy at the specified path.
:
{
  : existing
  :
  {
    : to-non-existing
    :
    {
      touch a;

      $* a b >>/~%EOO% &b;
        %create .+/b true%
        %create .+/b false%
        EOO

      test -f b
    }

    : to-existing
    :
    {
      touch a b;

      $* a b >>/~%EOO%
        %create .+/b true%
        %create .+/b false%
        EOO
    }

    : to-dir
    :
    {
      touch a;
      mkdir b;

      $* a b >>/~%EOO% 2>>/~%EOE% != 0
        %create .+/b true%
        EOO
        %cp: unable to copy file '.+/a' to '.+/b': .+%
        EOE
    }
  }

  : non-existing
  :
  {
    $* a b >>/~%EOO% 2>>/~%EOE% != 0
      %create .+/b true%
      EOO
      %cp: unable to copy file '.+/a' to '.+/b': .+%
      EOE
  }

  : non-file
  :
  {
    mkdir a;

    $* a b >>/~%EOO% 2>>/~%EOE% != 0
      %create .+/b true%
      EOO
      %cp: unable to copy file '.+/a' to '.+/b': .+%
      EOE
  }
}

: dir
:
: Test synopsis 2: make a directory copy at the specified path.
:
{
  : existing
  :
  {
    : to-non-existing
    :
    {
      mkdir a;

      $* -r a b >>/~%EOO% &b/;
        %create .+/b/ true%
        %create .+/b/ false%
        EOO

      test -d b
    }

    : to-existing
    :
    {
      mkdir a b;

      $* -R a b >>/~%EOO% 2>>/~%EOE% != 0
        %create .+/b/ true%
        EOO
        %cp: unable to copy directory '.+/a' to '.+/b': .+%
        EOE
    }

    : to-file
    :
    {
      mkdir a;
      touch b;

      $* -r a b >>/~%EOO% 2>>/~%EOE% != 0
        %create .+/b/ true%
        EOO
        %cp: unable to copy directory '.+/a' to '.+/b': .+%
        EOE
    }

    : recursively
    :
    {
      mkdir -p a/b/c;
      touch a/x a/b/y;

      $* -r a d >>/~%EOO% &d/ &d/x &d/b/ &d/b/y &d/b/c/;
        %create .+/d/ true%
        %create .+/d/ false%
        %(
        %create .+/d/.+ true%
        %create .+/d/.+ false%
        %){4}
        EOO

      test -d d/b/c && test -f d/x && test -f d/b/y
    }
  }

  : non-existing
  :
  {
    $* -r a b >>/~%EOO% 2>>/~%EOE% &b/ != 0
      %create .+/b/ true%
      %create .+/b/ false%
      EOO
      %cp: unable to copy directory '.+/a' to '.+/b': .+%
      EOE
  }

  : non-dir
  :
  {
    touch a;

    $* -r a b >>/~%EOO% 2>>/~%EOE% &b/ != 0
      %create .+/b/ true%
      %create .+/b/ false%
      EOO
      %cp: unable to copy directory '.+/a' to '.+/b': .+%
      EOE
  }
}

: files
:
: Test synopsis 3: copy files into the specified directory.
:
{
  : existing
  :
  {
    : into-dir
    :
    {
      : over-non-existing
      :
      {
        mkdir b;
        touch a;

        $* a b/ >>/~%EOO% &b/a;
          %create .+/b/a true%
          %create .+/b/a false%
          EOO

        test -f b/a
      }

      : over-dir
      :
      {
        mkdir -p b/a;
        touch a;

        $* a b/ >>/~%EOO% 2>>/~%EOE% != 0
          %create .+/b/a true%
          EOO
          %cp: unable to copy file '.+/a' to '.+/b/a': .+%
          EOE
      }

      : multiple
      :
      {
        touch a b;
        mkdir c;

        $* a b c/ >>/~%EOO% &c/a &c/b &c/;
          %create .+/c/a true%
          %create .+/c/a false%
          %create .+/c/b true%
          %create .+/c/b false%
          EOO

        test -f c/a && test -f c/b
      }
    }

    : into-non-existing-dir
    :
    {
      touch a;

      $* a b/ >>/~%EOO% 2>>/~%EOE% != 0
        %create .+/b/a true%
        EOO
        %cp: unable to copy file '.+/a' to '.+/b/a': .+%
        EOE
    }

    : into-non-dir
    :
    {
      touch a b;

      $* a b/ >>/~%EOO% 2>>/~%EOE% != 0
        %create .+/b/a true%
        EOO
        %cp: unable to copy file '.+/a' to '.+/b/a': .+%
        EOE
    }
  }

  : non-existing
  :
  {
    mkdir b;

    $* a b/ >>/~%EOO% 2>>/~%EOE% != 0
      %create .+/b/a true%
      EOO
      %cp: unable to copy file '.+/a' to '.+/b/a': .+%
      EOE
  }

  : non-file
  :
  {
    mkdir a b;

    $* a b/ >>/~%EOO% 2>>/~%EOE% != 0
      %create .+/b/a true%
      EOO
      %cp: unable to copy file '.+/a' to '.+/b/a': .+%
      EOE
  }
}

: filesystem-entries
:
: Test synopsis 4: copy filesystem entries into the specified directory.
:
{
  : file
  :
  {
    mkdir b;
    touch a;

    $* -R a b/ >>/~%EOO% &b/a;
      %create .+/b/a true%
      %create .+/b/a false%
      EOO

    test -f b/a
  }

  : dir
  :
  {
    : over-non-existing
    :
    {
      mkdir a b;
      touch a/c;

      $* -R a b/ >>/~%EOO% &b/a/ &b/a/c;
        %create .+/b/a/ true%
        %create .+/b/a/ false%
        %create .+/b/a/c true%
        %create .+/b/a/c false%
        EOO

      test -f b/a/c
    }

    : over-existing
    :
    {
      mkdir -p a b/a;

      $* -R a b/ >>/~%EOO% 2>>/~%EOE% != 0
        %create .+/b/a/ true%
        EOO
        %cp: unable to copy directory '.+/a' to '.+/b/a': .+%
        EOE
    }
  }
}

: attrs
:
if ($cxx.target.class != 'windows')
{
  fs = 's/.+ (\S+\s+\S+\s+\S+)\s+cp-file/\1/p'
  ds = 's/.+ (\S+\s+\S+\s+\S+)\s+cp-dir/\1/p'

  : copy
  :
  {
    : file
    :
    {
      ls -l $src_base/cp-dir | sed -n -e "$fs" | set t;

      $* -p $src_base/cp-dir/cp-file ./ >! &cp-file;

      ls -l | sed -n -e "$fs" >"$t"
    }

    : dir
    :
    {
      ls -l $src_base | sed -n -e "$ds" | set t;

      $* -pr $src_base/cp-dir ./ >! &cp-dir/ &cp-dir/cp-file;

      ls -l | sed -n -e "$ds" >"$t"
    }
  }

  : no-copy
  :
  : Note that the `ls -l` command by default displays the filesystem entry
  : modification time with the minute resolution and building from git
  : repository may not preserve the filesystem entry original modification
  : times. That is why we also pass --full-time and enable the test for only
  : platforms where ls supports this option.
  :
  if ($cxx.target.class == 'linux')
  {
    : file
    :
    {
      ls -l --full-time $src_base/cp-dir | sed -n -e "$fs" | set t;

      $* $src_base/cp-dir/cp-file ./ >! &cp-file;

      ls -l --full-time | sed -n -e "$fs" | set tn;

      if ("$tn" == "$t")
        exit "unexpectedly copied timestamp \($t\)"
      end
    }

    : dir
    :
    {
      ls -l --full-time $src_base | sed -n -e "$ds" | set t;

      $* -r $src_base/cp-dir ./ >! &cp-dir/ &cp-dir/cp-file;

      ls -l --full-time | sed -n -e "$ds" | set tn;

      if ("$tn" == "$t")
        exit "unexpectedly copied timestamp \($t\)"
      end
    }
  }
}

: cwd
:
: When cross-testing we cannot guarantee that host absolute paths are
: recognized by the target process.
:
if ($test.target == $build.host)
{
  test.options += -d $~/a;
  mkdir -p a/b;

  $* -R b c >>/~%EOO% &a/c/;
    %create .+/a/c/ true%
    %create .+/a/c/ false%
    EOO

  test -d a/c
}