# file      : tests/pkg-drop.testscript
# license   : MIT; see accompanying LICENSE file

.include common.testscript config.testscript remote.testscript

# Source repository (see pkg-build for details):
#
# pkg-drop
# |-- t4a
# |-- t4b
# |-- t4c
# |-- t4d
# `-- t7a

# Prepare repositories used by tests if running in the local mode.
#
+if! $remote
  rep_create += 2>!

  cp -r $src/t4a $out/t4a && $rep_create $out/t4a &$out/t4a/packages.manifest
  cp -r $src/t4b $out/t4b && $rep_create $out/t4b &$out/t4b/packages.manifest
  cp -r $src/t4c $out/t4c && $rep_create $out/t4c &$out/t4c/packages.manifest
  cp -r $src/t4d $out/t4d && $rep_create $out/t4d &$out/t4d/packages.manifest
  cp -r $src/t7a $out/t7a && $rep_create $out/t7a &$out/t7a/packages.manifest
end

cfg_create += 2>!
cfg_link   += 2>!
pkg_build  += -d cfg --yes 2>!
pkg_status += -d cfg
rep_add    += -d cfg 2>!
rep_fetch  += -d cfg --auth all --trust-yes 2>!

: no-name
:
$clone_cfg;
$* 2>>EOE != 0
  error: package name argument expected
    info: run 'bpkg help pkg-drop' for more information
  EOE

: unknown-package
:
$clone_cfg;
$* libfoo 2>>/EOE != 0
  error: package libfoo does not exist in configuration cfg/
  EOE

: invalid-name
:
$clone_cfg;
$* libfoo/1.0.0 2>>~%EOE% != 0
  %error: invalid package name 'libfoo/1.0.0': illegal character%
  EOE

: dependencies-or-dependents
:
{
  +$clone_cfg && $rep_add $rep/t4c && $rep_fetch
  +$pkg_build libbaz

  test.arguments += --print-only

  : foo-baz-bar
  :
  $clone_cfg;
  $* -y libfoo libbaz libbar >>EOO
    drop libbaz
    drop libbar
    drop libfoo
    EOO

  : dependents
  :
  {
    # Prepare the nested tests to use configuration from the enclosing
    # 'dependencies-or-dependents' group scope.
    #
    clone_cfg = cp -r $~/../cfg ./

    : unconfirmed
    :
    {
      test.arguments += --yes

      : libfoo
      :
      $clone_cfg;
      $* libfoo 2>>EOE != 0
        following dependent packages will have to be dropped as well:
          libbar (requires libfoo)
          libbaz (requires libbar)
        error: refusing to drop dependent packages with just --yes
          info: specify --drop-dependent to confirm
        EOE

      : libfoo-libbar
      :
      $clone_cfg;
      $* libfoo libbar 2>>EOE != 0
        following dependent packages will have to be dropped as well:
          libbaz (requires libbar)
        error: refusing to drop dependent packages with just --yes
          info: specify --drop-dependent to confirm
        EOE

      : libfoo-libbaz
      :
      $clone_cfg;
      $* libfoo libbaz 2>>EOE != 0
        following dependent packages will have to be dropped as well:
          libbar (requires libfoo)
        error: refusing to drop dependent packages with just --yes
          info: specify --drop-dependent to confirm
        EOE
    }

    : confirmed
    :
    {
      test.arguments += --drop-dependent

      : libfoo
      :
      $clone_cfg;
      $* libfoo >>EOO
        drop libbaz
        drop libbar
        drop libfoo
        EOO

      : libfoo-libbaz
      :
      $clone_cfg;
      $* libfoo libbaz >>EOO
        drop libbaz
        drop libbar
        drop libfoo
        EOO

      : libbaz-libfoo
      :
      $clone_cfg;
      $* libbaz libfoo >>EOO
        drop libbaz
        drop libbar
        drop libfoo
        EOO
    }
  }

  : dependencies
  :
  {
    # Prepare the nested tests to use configuration from the enclosing
    # 'dependencies-or-dependents' group scope.
    #
    clone_cfg = cp -r $~/../cfg ./

    : libbaz
    :
    $clone_cfg;
    $* -y libbaz >>EOO
      drop libbaz
      drop libbar
      drop libfoo
      EOO

    : libbaz-only
    :
    $clone_cfg;
    $* -n libbaz >>EOO
      drop libbaz
      EOO

    : libbar-libbaz
    :
    $clone_cfg;
    $* -n libbar libbaz >>EOO
      drop libbaz
      drop libbar
      EOO

    : libbaz-libbar
    :
    $clone_cfg;
    $* -n libbaz libbar >>EOO
      drop libbaz
      drop libbar
      EOO

    : dependencies
    :
    : Note that we do not move this test to the dependencies-and-dependents
    : group as the configuration repository set would be different.
    :
    $clone_cfg;
    $* -y --drop-dependent libbar >>EOO
      drop libbaz
      drop libbar
      drop libfoo
      EOO
  }

  # Here we combine the test group teardown and the "actual drop" test.
  #
  -$pkg_drop -d cfg --yes libbaz 2>>EOE
     disfigured libbaz
     disfigured libbar
     disfigured libfoo
     purged libbaz
     purged libbar
     purged libfoo
     EOE

   -$pkg_status libbar/1.1.0 >'libbar available [1.1.0]'
   -$pkg_status libbaz/1.1.0 >'libbaz available 1.1.0'
   -$pkg_status libfoo/1.1.0 >'libfoo available [1.1.0]'
}

: dependencies-and-dependents
:
{
  +$clone_cfg && $rep_add $rep/t4d && $rep_fetch
  +$pkg_build libbiz

  clone_cfg = cp -r ../../cfg ./
  test.arguments += --print-only

  : drop-dependencies-no-dependents
  :
  {
    test.arguments += --yes

    : libbiz
    :
    $clone_cfg;
    $* libbiz >>EOO
      drop libbiz
      drop libbaz
      drop libbar
      drop libfoo
      drop libfox
      EOO

    : libfox-libbiz
    :
    $clone_cfg;
    $* libfox libbiz >>EOO
      drop libbiz
      drop libfox
      drop libbaz
      drop libbar
      drop libfoo
      EOO
  }

  : drop-dependencies
  :
  {
    test.arguments += --yes --drop-dependent

    : libfox
    :
    $clone_cfg;
    $* libfox >>EOO
      drop libbiz
      drop libfox
      drop libbaz
      drop libbar
      drop libfoo
      EOO

    : libbaz
    :
    $clone_cfg;
    $* libbaz >>EOO
      drop libbiz
      drop libbaz
      drop libbar
      drop libfoo
      drop libfox
      EOO

    : libbar
    :
    $clone_cfg;
    $* libbar >>EOO
      drop libbiz
      drop libbaz
      drop libbar
      drop libfoo
      drop libfox
      EOO

    : libfoo
    :
    $clone_cfg;
    $* libfoo >>EOO
      drop libbiz
      drop libbaz
      drop libbar
      drop libfoo
      drop libfox
      EOO
  }

  : keep-dependencies
  {
    test.arguments += --no --drop-dependent

    : fox-baz
    :
    $clone_cfg;
    $* libfox libbaz >>EOO
      drop libbiz
      drop libfox
      drop libbaz
      EOO

    : libbaz-libfox
    :
    $clone_cfg;
    $* libbaz libfox >>EOO
      drop libbiz
      drop libbaz
      drop libfox
      EOO

    : libfox-libbar
    :
    $clone_cfg;
    $* libfox libbar >>EOO
      drop libbiz
      drop libfox
      drop libbaz
      drop libbar
      EOO

    : libbar-libfox
    :
    $clone_cfg;
    $* libbar libfox >>EOO
      drop libbiz
      drop libbaz
      drop libbar
      drop libfox
      EOO
  }

  -$pkg_drop -d cfg --yes --drop-dependent libbar 2>>EOE
     disfigured libbiz
     disfigured libbaz
     disfigured libbar
     disfigured libfoo
     disfigured libfox
     purged libbiz
     purged libbaz
     purged libbar
     purged libfoo
     purged libfox
     EOE

   -$pkg_status libfox/1.0.0 >'libfox available 1.0.0'
   -$pkg_status libfoo/1.1.0 >'libfoo available [1.1.0]'
   -$pkg_status libbar/1.1.0 >'libbar available [1.1.0]'
   -$pkg_status libbaz/1.1.0 >'libbaz available 1.1.0'
   -$pkg_status libbiz/1.0.0 >'libbiz available 1.0.0'
}

: keep-drop-options
:
: Test --drop-dependent, --keep-dependent, --keep-unused, option.
:
{
  +$clone_cfg && $rep_add $rep/t4b && $rep_fetch

  : keep-drop-dependent
  :
  {
    $clone_cfg && $pkg_build libbar;

    $* --keep-dependent libfoo 2>>EOE != 0;
      error: following dependent packages will have to be dropped as well:
        libbar (requires libfoo)
      EOE

    $* --drop-dependent libfoo 2>>EOE
      disfigured libbar
      disfigured libfoo
      purged libbar
      purged libfoo
      EOE
  }

  : drop-dependency
  :
  {
    $clone_cfg && $pkg_build libbar;

    $* libbar --yes 2>>EOE
      disfigured libbar
      disfigured libfoo
      purged libbar
      purged libfoo
      EOE
  }

  : keep-dependency
  :
  {
    $clone_cfg && $pkg_build libbar;

    $* --keep-unused libbar 2>>EOE;
      disfigured libbar
      purged libbar
      EOE

    $pkg_status libfoo >'libfoo configured 1.1.0';

    $* libfoo 2>>EOE
      disfigured libfoo
      purged libfoo
      EOE
  }
}

: disfigure-only
:
: Test --disfigure-only option.
:
{
  $clone_cfg && $rep_add $rep/t4a && $rep_fetch;
  $pkg_build libfoo;

  $* --disfigure-only libfoo 2>'disfigured libfoo';
  $pkg_status libfoo >'!libfoo unpacked 1.1.0';

  $* libfoo 2>'purged libfoo'
}

: linked-configs
:
{
  pkg_build = $0 pkg-build --yes 2>!

  : 3-configs
  :
  {
    +$clone_root_cfg && $rep_add $rep/t4c && $rep_fetch

    +$cfg_create -d cfg-bar &cfg-bar/***
    +$cfg_create -d cfg-foo &cfg-foo/***

    +$cfg_link -d cfg     cfg-bar
    +$cfg_link -d cfg-bar cfg-foo

    : baz
    :
    {
      $clone_cfg;
      cp -pr ../cfg-bar ./;
      cp -pr ../cfg-foo ./;

      $pkg_build -d cfg-bar libbar@"$rep/t4b" ?libfoo +{ --config-id 2 } \
                 --trust-yes;

      $pkg_build -d cfg libbaz;

      $pkg_build -d cfg '?libbar' +{ --config-id 1 };

      $* libbaz <<EOI 2>>/~%EOE%
          y
          y
          EOI
          following dependencies were automatically built but will no longer be used:
            libbar [cfg-bar/]
            libfoo [cfg-foo/]
          %drop unused packages\? \[Y.n\]   drop libbaz%
            drop libbar [cfg-bar/]
            drop libfoo [cfg-foo/]
          %continue\? \[Y.n\] disfigured libbaz%
          disfigured libbar [cfg-bar/]
          disfigured libfoo [cfg-foo/]
          purged libbaz
          purged libbar [cfg-bar/]
          purged libfoo [cfg-foo/]
          EOE
    }

    : foo
    :
    {
      $clone_cfg;
      cp -pr ../cfg-bar ./;
      cp -pr ../cfg-foo ./;

      $pkg_build -d cfg-bar libbar@"$rep/t4b" ?libfoo +{ --config-id 2 } \
                 --trust-yes;

      $pkg_build -d cfg libbaz;

      # Make sure that dependents of a package being dropped can be found in
      # implicitly linked configurations recursively. Note that configuring
      # libbar as system, we make libbaz an only dependent of libfoo.
      #
      $pkg_build -d cfg '?sys:libbar' +{ --config-id 1 };

      $pkg_status -r libbaz >>/EOO;
        !libbaz configured 1.1.0
          libbar [cfg-bar/] configured,system !* available [1.1.0]
          libfoo [cfg-foo/] configured 1.1.0
        EOO

        $pkg_status -d cfg-bar -r libbar >>EOO;
          libbar configured,system !* available 1.1.0
          EOO

        $pkg_status -d cfg-foo libfoo >'libfoo configured 1.1.0';

        $* -d cfg-foo libfoo <<EOI 2>>/~%EOE%;
          y
          y
          y
          EOI
          following dependent packages will have to be dropped as well:
            libbaz [cfg/] (requires libfoo)
          %drop dependent packages\? \[y.N\] following dependencies were automatically built but will no longer be used:%
            sys:libbar [cfg-bar/]
          %drop unused packages\? \[Y.n\]   drop libbaz \[cfg/\]%
            drop libfoo
            drop libbar [cfg-bar/]
          %continue\? \[Y.n\] disfigured libbaz \[cfg/\]%
          disfigured libfoo
          purged libbar [cfg-bar/]
          purged libbaz [cfg/]
          purged libfoo
          EOE

      $pkg_status            libbaz >'libbaz available 1.1.0';
      $pkg_status -d cfg-bar libbar >'libbar available 1.1.0';
      $pkg_status -d cfg-foo libfoo >'libfoo unknown'
    }

    : bar
    :
    {
      $clone_cfg;
      cp -pr ../cfg-bar ./;
      cp -pr ../cfg-foo ./;

      # Test that if we turn implicit links into explicit, then all dependents
      # are still discovered.
      #
      $cfg_link -d cfg-bar cfg;
      $cfg_link -d cfg-foo cfg-bar;

      $pkg_build -d cfg-bar libbar@"$rep/t4b" ?libfoo +{ --config-id 2 } \
                 --trust-yes;

      $pkg_build -d cfg libbaz;

      $pkg_status -r libbaz >>/EOO;
        !libbaz configured 1.1.0
          !libbar [cfg-bar/] configured !1.1.0
            libfoo [cfg-foo/] configured 1.1.0
          libfoo [cfg-foo/] configured 1.1.0
        EOO

      $pkg_status -d cfg-bar -r libbar >>/EOO;
        !libbar configured !1.1.0
          libfoo [cfg-foo/] configured 1.1.0
        EOO

      $pkg_status -d cfg-foo libfoo >'libfoo configured 1.1.0';

      $* -d cfg-bar libbar <<EOI 2>>/~%EOE%;
        y
        y
        y
        EOI
        following dependent packages will have to be dropped as well:
          libbaz [cfg/] (requires libbar)
        %drop dependent packages\? \[y.N\] following dependencies were automatically built but will no longer be used:%
          libfoo [cfg-foo/]
        %drop unused packages\? \[Y.n\]   drop libbaz \[cfg/\]%
          drop libbar
          drop libfoo [cfg-foo/]
        %continue\? \[Y.n\] disfigured libbaz \[cfg/\]%
        disfigured libbar
        disfigured libfoo [cfg-foo/]
        purged libbaz [cfg/]
        purged libbar
        purged libfoo [cfg-foo/]
        EOE

      $pkg_status            libbaz >'libbaz available 1.1.0';
      $pkg_status -d cfg-bar libbar >'libbar available 1.1.0';
      $pkg_status -d cfg-foo libfoo >'libfoo unknown'
    }
  }
}

: buildtime-dep
:
{
  +$clone_cfg && $rep_add $rep/t7a && $rep_fetch
  +$cfg_create -d cfg2 --type host &cfg2/***
  +$cfg_link -d cfg cfg2

  : drop-dependent
  :
  {
    $clone_cfg;
    cp -pr ../cfg2 ./;

    $pkg_build libbar --yes &cfg2/.bpkg/build2/***;

    $* libbar <<EOI 2>>/~%EOE%;
      y
      y
      EOI
      following dependencies were automatically built but will no longer be used:
        foo [cfg2/]
        libbaz [cfg2/]
        libbuild2-bar [cfg2/.bpkg/build2/]
        libbaz
      %drop unused packages\? \[Y.n\]   drop libbar%
        drop foo [cfg2/]
        drop libbaz [cfg2/]
        drop libbuild2-bar [cfg2/.bpkg/build2/]
        drop libbaz
      %continue\? \[Y.n\] disfigured libbar%
      disfigured foo [cfg2/]
      disfigured libbaz [cfg2/]
      disfigured libbuild2-bar [cfg2/.bpkg/build2/]
      disfigured libbaz
      purged libbar
      purged foo [cfg2/]
      purged libbaz [cfg2/]
      purged libbuild2-bar [cfg2/.bpkg/build2/]
      purged libbaz
      EOE

    $pkg_status -r libbar >'libbar available 1.0.0'
  }

  : drop-dependency
  :
  {
    $clone_cfg;
    cp -pr ../cfg2 ./;

    $pkg_build libbar --yes &cfg2/.bpkg/build2/***;

    $* -d cfg2 libbaz <<EOI 2>>/~%EOE%;
      y
      y
      y
      EOI
      following dependent packages will have to be dropped as well:
        foo (requires libbaz)
        libbar [cfg/] (requires foo)
      %drop dependent packages\? \[y.N\] following dependencies were automatically built but will no longer be used:%
        libbuild2-bar [cfg2/.bpkg/build2/]
        libbaz [cfg/]
      %drop unused packages\? \[Y.n\]   drop libbar \[cfg/\]%
        drop foo
        drop libbaz
        drop libbuild2-bar [cfg2/.bpkg/build2/]
        drop libbaz [cfg/]
      %continue\? \[Y.n\] disfigured libbar \[cfg/\]%
      disfigured foo
      disfigured libbaz
      disfigured libbuild2-bar [cfg2/.bpkg/build2/]
      disfigured libbaz [cfg/]
      purged libbar [cfg/]
      purged foo
      purged libbaz
      purged libbuild2-bar [cfg2/.bpkg/build2/]
      purged libbaz [cfg/]
      EOE

    $pkg_status -r libbar >'libbar available 1.0.0'
  }

  : drop-private-dependency
  :
  {
    $clone_root_cfg && $rep_add $rep/t7a && $rep_fetch;

    $pkg_build libbar --yes &cfg/.bpkg/host/*** &cfg/.bpkg/build2/***;

    $* -d cfg/.bpkg/build2/ libbuild2-bar <<EOI 2>>/~%EOE%
      y
      y
      y
      EOI
      following dependent packages will have to be dropped as well:
        foo [cfg/.bpkg/host/] (requires libbuild2-bar)
        libbar [cfg/] (requires foo [cfg/.bpkg/host/])
      %drop dependent packages\? \[y.N\] following dependencies were automatically built but will no longer be used:%
        libbaz [cfg/.bpkg/host/]
        libbaz [cfg/]
      %drop unused packages\? \[Y.n\]   drop libbar \[cfg/\]%
        drop foo [cfg/.bpkg/host/]
        drop libbuild2-bar
        drop libbaz [cfg/.bpkg/host/]
        drop libbaz [cfg/]
      %continue\? \[Y.n\] disfigured libbar \[cfg/\]%
      disfigured foo [cfg/.bpkg/host/]
      disfigured libbuild2-bar
      disfigured libbaz [cfg/.bpkg/host/]
      disfigured libbaz [cfg/]
      purged libbar [cfg/]
      purged foo [cfg/.bpkg/host/]
      purged libbuild2-bar
      purged libbaz [cfg/.bpkg/host/]
      purged libbaz [cfg/]
      EOE
  }

  : skip-deleted-dependency
  :
  {
    $clone_cfg;
    cp -pr ../cfg2 ./;

    $pkg_build libbar --yes &cfg/lib*/*** &cfg/lib* &cfg2/.bpkg/build2/***;

    mv cfg cfg.tmp;

    $* -d cfg2 libbaz <<EOI 2>>/~%EOE%;
      y
      y
      y
      EOI
      following dependent packages will have to be dropped as well:
        foo (requires libbaz)
      %drop dependent packages\? \[y.N\] following dependencies were automatically built but will no longer be used:%
        libbuild2-bar [cfg2/.bpkg/build2/]
      %drop unused packages\? \[Y.n\]   drop foo%
        drop libbaz
        drop libbuild2-bar [cfg2/.bpkg/build2/]
      %continue\? \[Y.n\] disfigured foo%
      disfigured libbaz
      disfigured libbuild2-bar [cfg2/.bpkg/build2/]
      purged foo
      purged libbaz
      purged libbuild2-bar [cfg2/.bpkg/build2/]
      EOE

    # While at it, test that we properly handle the missing prerequisite
    # situation.
    #
    mv cfg.tmp cfg;

    $* libbar 2>>/EOE != 0;
      error: unable to find prerequisite package foo in linked configuration cfg2/
      EOE

    $pkg_status -d cfg2 -r 2>>EOE
      info: no held packages in the configuration
        info: use --all|-a to see status of all packages
      EOE
  }
}