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

# Here we test both init and deinit commands.
#

.include common.testscript project.testscript

config_cxx = [cmdline] cc config.cxx=$quote($recall($cxx.path) $cxx.config.mode, true)

new    += --vcs git,branch=master
status += -d prj

: create-cfg
:
{
  +$clone_prj

  deinit += -d prj

  : with-dependency
  :
  {
    +$clone_prj

    +cat <<EOI >+prj/manifest
      depends: libprj
      EOI

    : cfg-pkg-args
    :
    {
      $clone_prj;

      $* -C @cfg $config_cxx 'config.cc.poptions=-DTEST' -- '?sys:libprj/*' 2>>/~"%EOE%" &prj-cfg/***;
        initializing in project $~/prj/
        created configuration @cfg $~/prj-cfg/ 1 target default,forwarded,auto-synchronized
        synchronizing:
        %  configure sys:libprj.*%
        %  new prj.+19700101000000%
        EOE

      sed -n -e 's/^config.cc.poptions = (.+)$/\1/p' prj-cfg/build/config.build \
        >'-DTEST';

      $status >'prj configured 0.1.0-a.0.19700101000000';

      $build prj/ 2>>~%EOE%;
        %(mkdir|c\+\+|ld|ln) .+%{4}
        EOE

      prj/prj/prj 'testscript' >'Hello, testscript!'; # Make sure is forwarded.

      $build prj-cfg/prj/ 2>>/EOE;
        info: prj-cfg/dir{prj/} is up to date
        EOE

      $build 'clean:' prj/ 2>>~%EOE%;
        %(rm|rmdir) .+%{3}
        EOE

      $deinit 2>>/"EOE"
        deinitializing in project $~/prj/
        synchronizing:
          drop prj
          drop libprj
        EOE
    }

    : cfg-pkg-args-sep
    :
    {
      $clone_prj;

      $* -C @cfg -- $config_cxx 'config.cc.poptions=-DTEST' -- '?sys:libprj/*' 2>>/~"%EOE%" &prj-cfg/***;
        initializing in project $~/prj/
        created configuration @cfg $~/prj-cfg/ 1 target default,forwarded,auto-synchronized
        synchronizing:
        %  configure sys:libprj.*%
        %  new prj.+19700101000000%
        EOE

      sed -n -e 's/^config.cc.poptions = (.+)$/\1/p' prj-cfg/build/config.build \
        >'-DTEST';

      $deinit 2>>/"EOE"
        deinitializing in project $~/prj/
        synchronizing:
          drop prj
          drop libprj
        EOE
    }

    : pkg-args
    :
    {
      $clone_prj;

      # Note that not passing the C++ configuration arguments (see above) for
      # the sake of testing, we may end up with the 'not built with default C++
      # compiler' error. To avoid this, we just make sure this is not a C++
      # project.
      #
      echo ''            >=prj/build/root.build;
      echo './: prj.cxx' >=prj/prj/buildfile;

      $* -C @cfg -- -- '?sys:libprj/*' 2>>/~"%EOE%" &prj-cfg/***;
        initializing in project $~/prj/
        created configuration @cfg $~/prj-cfg/ 1 target default,forwarded,auto-synchronized
        synchronizing:
        %  configure sys:libprj.*%
        %  new prj.+19700101000000%
        EOE

      $deinit 2>>/"EOE"
        deinitializing in project $~/prj/
        synchronizing:
          drop prj
          drop libprj
        EOE
    }
  }

  : no-module
  :
  {
    $clone_prj;

    $* -C @cfg 2>>~%EOE% != 0;
      %initializing in project .+%
      error: no build system module(s) specified for configuration to be created
        info: for example, for C/C++ configuration, specify 'cc'
        info: use '--' to create configuration without modules
        info: for example: bdep init -C ... --
      EOE

    $* -C @cfg -- 2>>/~"%EOE%" &prj-cfg/***;
      initializing in project $~/prj/
      created configuration @cfg $~/prj-cfg/ 1 target default,forwarded,auto-synchronized
      synchronizing:
      %  new prj.+19700101000000%
      EOE

    $deinit 2>>/"EOE"
      deinitializing in project $~/prj/
      synchronizing:
        drop prj
      EOE
  }
}

: add-cfg
:
{
  $clone_prj;

  deinit += -d prj;

  cat <<EOI >+prj/manifest;
    depends: libprj
    EOI

  # Pre-create configurations.
  #
  $new  -C prj-cfg1 --no-default          tmp $config_cxx 2>! &prj-cfg1/*** &tmp/***;
  $init -C prj-cfg2 --config-type host -d tmp $config_cxx 2>! &prj-cfg2/***;

  $* -A @cfg1 '?sys:libprj/*' 2>>/~"%EOE%";
    initializing in project $~/prj/
    added configuration @cfg1 $~/prj-cfg1/ 1 target default,forwarded,auto-synchronized
    synchronizing:
    %  configure sys:libprj.*%
    %  new prj.+19700101000000%
    EOE

  $* -A prj-cfg2 --no-default @cfg2 '?sys:libprj/*' 2>>/~"%EOE%";
    initializing in project $~/prj/
    added configuration @cfg2 $~/prj-cfg2/ 2 host auto-synchronized
    synchronizing:
    %  configure sys:libprj.*%
    %  new prj.+19700101000000%
    EOE

  $status --all >>EOO;
    in configuration @cfg1:
    prj configured 0.1.0-a.0.19700101000000

    in configuration @cfg2:
    prj configured 0.1.0-a.0.19700101000000
    EOO

  $build prj-cfg1/ 2>>~%EOE%;
    %(mkdir|c\+\+|ld) .+%{6}
    EOE

  $build prj-cfg2/ 2>>~%EOE%;
    %(mkdir|c\+\+|ld) .+%{6}
    EOE

  $build prj/ 2>>~%EOE%;
    %(ln|info:) .+%{2}
    EOE

  $build 'clean:' prj/ 2>>~%EOE%;
    %(rm|rmdir) .+%{3}
    EOE

  $deinit 2>>/"EOE"
    deinitializing in project $~/prj/
    synchronizing:
      drop prj
      drop libprj
    EOE
}

: pkg
:
: Test initializing a package while creating it inside an already existing
: project.
:
{
  deinit += -d prj;

  # Create (and build) the executable single-package project.
  #
  cp --no-cleanup -pr ../prj ./ &prj/***;

  $* -C @cfg $config_cxx 2>>/~"%EOE%" &prj-cfg/***;
    initializing in project $~/prj/
    created configuration @cfg $~/prj-cfg/ 1 target default,forwarded,auto-synchronized
    synchronizing:
    %  new prj.+19700101000000%
    EOE

  $status >'prj configured 0.1.0-a.0.19700101000000';

  $build prj/ 2>>~%EOE%;
    %(mkdir|c\+\+|ld|ln) .+%{4}
    EOE

  # Move the executable package into a separate directory.
  #
  mkdir --no-cleanup prj/prj.pkg;

  mv prj/prj prj/build prj/buildfile prj/manifest prj/README.md \
     prj/.gitignore prj/prj.pkg/;

  mv prj/prj.pkg prj/prj;

  cat <<EOI >=prj/packages.manifest;
    : 1
    location: prj/
    EOI

  # Add the library package.
  #
  $new --package -t lib libprj -d prj 2>>/"EOE";
    created new library package libprj in $~/prj/libprj/
    EOE

  # While at it, make sure we fail if misspell the package directory.
  #
  mkdir prj/libpr;
  $init --all -d prj/libpr 2>>/~"%EOE%" != 0;
    error: prj/libpr/ is not a package or project directory
    EOE

  $init --all -d prj/libprj 2>>/~"%EOE%";
    initializing in project $~/prj/
    synchronizing:
    %  upgrade prj.+19700101000000#1%
    %  new libprj.+19700101000000%
    EOE

  # Factor out some of the executable package functionality into the library.
  #
  cat <<EOI >+prj/prj/manifest;
    depends: libprj
    EOI

  sed -i -e 's/^(#import .+)$/import libs += libprj%lib{prj}/' \
      prj/prj/prj/buildfile;

  cat <<EOI >=prj/prj/prj/prj.cxx;
    #include <iostream>

    #include <libprj/prj.hxx>

    using namespace std;

    int main (int argc, char* argv[])
    {
      if (argc < 2)
      {
        cerr << "error: missing name" << endl;
        return 1;
      }

      prj::say_hello (cout, argv[1]);
    }
    EOI

  $build prj-cfg/prj/ 2>>/~"%EOE%";
    synchronizing $~/prj-cfg/:
    %  upgrade prj.+19700101000000#2%
    %\(mkdir|version|c\\+\\+|ld) .+%{6}
    EOE

  $deinit 2>>/"EOE"
    deinitializing in project $~/prj/
    deinitializing package prj
    deinitializing package libprj
    synchronizing:
      drop prj
      drop libprj
    EOE
}

: deinit-deorphan
:
{
  +$clone_prj

  +cat <<EOI >+prj/manifest
    depends: libprj
    EOI

  +$new -t lib -o libprj.git libprj &libprj.git/*** 2>!

  g = [cmdline] git -C libprj.git 2>! >&2

  +$g config user.name 'Test Script'
  +$g config user.email 'testscript@example.com'
  +$g add '*'
  +$g commit -m 'Create' --no-verify

  : dependency-only
  :
  {
    $clone_prj;
    cp -rp ../libprj.git ./;

    cat <<EOI >+prj/repositories.manifest;
      :
      role: prerequisite
      location: ../libprj.git#master
      EOI

    $* $config_cxx -C @cfg &prj-cfg/*** 2>!;

    git clone libprj.git &libprj/*** 2>! >&2;

    $init -d libprj -A prj-cfg 2>>/~"%EOE%";
      initializing in project $~/libprj/
      added configuration $~/prj-cfg/ 1 target default,forwarded,auto-synchronized
      %fetching .+%
      %querying .+%
      synchronizing:
      %  upgrade libprj.0.1.0-a.0.+#1%
      %  reconfigure prj.0.1.0-a.0.19700101000000%
      EOE

    $build prj/ 2>>/~%EOE%;
      %(mkdir|c\+\+|ld|ln) .+%{4}
      EOE

    $deinit -d libprj 2>>/~"%EOE%";
      deinitializing in project $~/libprj/
      deinitializing in replacement mode due to existing dependents
      %fetching dir:.+/libprj%
      %fetching dir:.+/prj%
      %fetching git:.+/libprj#.+ \\\(prerequisite of dir:.+/prj\\\)%
      querying $~/libprj.git
      synchronizing:
      %  replace.downgrade.unhold libprj.0.1.0-a.0.+%
      %  reconfigure prj.0.1.0-a.0.+%
      verifying symlinks...
      %fixing up symlinks...%?
      %distributing libprj.0.1.0-a.0.+%
      EOE

    $build prj/ 2>>/~%EOE%;
      %ln prj-cfg/prj/prj/exe\{prj\} -> prj/prj/%?
      info: prj-cfg/dir{prj/} is up to date
      EOE

    $build 'clean:' prj/ 2>>~%EOE%;
      %(rm|rmdir) .+%{3}
      EOE

    $deinit -d prj 2>>/"EOE"
      deinitializing in project $~/prj/
      synchronizing:
        drop prj
        drop libprj
      EOE
  }

  : not-only-dependency
  :
  : Similar to the above but with an additional libprj/libprj-extras library
  : which has no initialized dependents. Here we test that it is dropped while
  : being deorphaned.
  :
  {
    $clone_prj;

    $new -t empty -o libprj.git libprj &libprj.git/*** 2>!;
    $new --package -t lib libprj -d libprj.git 2>!;
    $new --package -t lib libprj-extras -d libprj.git 2>!;

    $g config user.name 'Test Script';
    $g config user.email 'testscript@example.com';
    $g add '*';
    $g commit -m 'Create' --no-verify;

    cat <<EOI >+prj/repositories.manifest;
      :
      role: prerequisite
      location: ../libprj.git#master
      EOI

    $* $config_cxx -C @cfg &prj-cfg/*** 2>!;

    git clone libprj.git &libprj/*** 2>! >&2;

    $init -d libprj -A prj-cfg 2>>/~"%EOE%";
      initializing in project $~/libprj/
      added configuration $~/prj-cfg/ 1 target default,forwarded,auto-synchronized
      initializing package libprj
      initializing package libprj-extras
      %fetching .+%
      %querying .+%
      synchronizing:
      %  upgrade libprj.0.1.0-a.0.+#1%
      %  new libprj-extras.0.1.0-a.0.+%
      %  reconfigure prj.0.1.0-a.0.19700101000000%
      EOE

    $build prj/ 2>>/~%EOE%;
      %(mkdir|c\+\+|ld|ln) .+%{4}
      EOE

    $deinit -d libprj 2>>/~"%EOE%";
      deinitializing in project $~/libprj/
      deinitializing package libprj
      deinitializing package libprj-extras
      deinitializing in replacement mode due to existing dependents
      %fetching dir:.+/libprj%
      %fetching dir:.+/prj%
      %fetching git:.+/libprj#.+ \\\(prerequisite of dir:.+/prj\\\)%
      querying $~/libprj.git
      synchronizing:
      %  drop libprj-extras.0.1.0-a.0.+ \\\(unused\\\)%
      %  replace.downgrade.unhold libprj.0.1.0-a.0.+%
      %  reconfigure prj.0.1.0-a.0.+%
      verifying symlinks...
      %fixing up symlinks...%?
      %distributing libprj.0.1.0-a.0.+%
      EOE

    $build prj/ 2>>/~%EOE%;
      %ln prj-cfg/prj/prj/exe\{prj\} -> prj/prj/%?
      info: prj-cfg/dir{prj/} is up to date
      EOE

    $build 'clean:' prj/ 2>>~%EOE%;
      %(rm|rmdir) .+%{3}
      EOE

    $deinit -d prj 2>>/"EOE"
      deinitializing in project $~/prj/
      synchronizing:
        drop prj
        drop libprj
      EOE
  }

  : not-found
  :
  {
    $clone_prj;
    cp -rp ../libprj.git ./;

    git clone libprj.git &libprj/*** 2>! >&2;

    $init $config_cxx -d libprj -C @cfg &libprj-cfg/*** 2>!;

    $* -A libprj-cfg 2>>/~"%EOE%";
      initializing in project $~/prj/
      added configuration $~/libprj-cfg/ 1 target default,forwarded,auto-synchronized
      synchronizing:
      %  new prj.0.1.0-a.0.19700101000000%
      EOE

    $build prj/ 2>>/~%EOE%;
      %(mkdir|c\+\+|ld|ln) .+%{4}
      EOE

    $deinit -d libprj 2>>/~"%EOE%" != 0;
      deinitializing in project $~/libprj/
      deinitializing in replacement mode due to existing dependents
      %fetching dir:.+/libprj%
      %fetching dir:.+/prj%
      error: libprj is not available from its dependents' repositories
      EOE

    # While at it, test that adding the repository to the dependent'
    # repositories manifest fixes the issue.
    #
    cat <<EOI >+prj/repositories.manifest;
      :
      role: prerequisite
      location: ../libprj.git#master
      EOI

    $deinit -d libprj 2>>/~"%EOE%";
      deinitializing in project $~/libprj/
      deinitializing in replacement mode due to existing dependents
      %fetching dir:.+/libprj%
      %fetching dir:.+/prj%
      %fetching git:.+/libprj#.+ \\\(prerequisite of dir:.+/prj\\\)%
      querying $~/libprj.git
      fetching from $~/libprj.git
      synchronizing:
      %  replace.unhold libprj.0.1.0-a.0.+%
      %  reconfigure prj.0.1.0-a.0.+%
      verifying symlinks...
      %fixing up symlinks...%?
      %distributing libprj.0.1.0-a.0.+%
      EOE

    $build prj/ 2>>/~%EOE%;
      %ln libprj-cfg/prj/prj/exe\{prj\} -> prj/prj/%?
      info: libprj-cfg/dir{prj/} is up to date
      EOE

    $build 'clean:' prj/ 2>>~%EOE%;
      %(rm|rmdir) .+%{3}
      EOE

    $deinit -d prj 2>>/"EOE"
      deinitializing in project $~/prj/
      synchronizing:
        drop prj
        drop libprj
      EOE
  }
}
