# file      : tests/recipe/cxx/testscript
# license   : MIT; see accompanying LICENSE file

# Ad hoc C++ recipes not supported in a statically-linked build system. Also
# disable when cross-testing for the sake of simplicity.
#
if (!$static && $test.target == $build.host)
{
  +mkdir build
  +cat <<EOI >=build/bootstrap.build
    project = test
    amalgamation =
    subprojects =

    using config
    using test
    EOI

  +cat <<EOI >=build/root.build
    EOI

  +cat <<EOI >=buildfile
    ./:
    {{ c++ 1
      // Dummy recipe to trigger cleanup.
    }}
    EOI

  +export BDEP_SYNC=0

  : update-clean
  :
  {
    echo 'bar' >=bar;

    cat <<EOI >=buildfile;
      foo: bar
      % update clean
      {{ c++ 1
        recipe
        apply (action a, target& xt) const override
        {
          file& t (xt.as<file> ());

          t.derive_path ();
          inject_fsdir (a, t);
          match_prerequisite_members (a, t);

          switch (a)
          {
          case perform_update_id:  return perform_update;
          case perform_clean_id:   return perform_clean_depdb;
          default: assert (false); return noop_recipe;
          }
        }

        static target_state
        perform_update (action a, const target& xt)
        {
          const file& t (xt.as<file> ());
          const path& tp (t.path ());

          timestamp mt (t.load_mtime ());
          auto pr (execute_prerequisites<file> (a, t, mt));

          bool update (!pr.first);
          target_state r (update ? target_state::changed : *pr.first);

          const file& s (pr.second);
          const path& sp (s.path ());

          depdb dd (tp + ".d");
          dd.expect (sp);

          if (dd.writing () || dd.mtime > mt)
            update = true;

          dd.close ();

          if (!update)
            return r;

          if (verb == 1)
            print_diag ("cp", s, t);
          else if (verb >= 2)
            text << "cp " << sp << ' ' << tp;

          cpfile (sp, tp);
          return target_state::changed;
        }
      }}
      EOI

    $* 2>>~%EOE%;
      %^(c\+\+|ld).*%+
      cp file{bar} -> file{foo}
      EOE

    cat <<<foo >'bar';

    # While at it, make sure there is no rebuild.
    #
    $* 2>/'info: dir{./} is up to date';

    $* clean 2>-
  }

  : test
  :
  {
    echo 'bar' >=bar;

    cat <<EOI >=buildfile;
      foo: bar
      {{
        cp $path($<) $path($>)
      }}
      % test
      {{ c++ 1 --

        #include <iostream>

        --

        recipe
        apply (action a, target& t) const override
        {
          if (a.outer ())
          {
            match_inner (a, t);
            return execute_inner;
          }
          else
            return perform_test;
        }

        static target_state
        perform_test (action, const target& xt)
        {
          const file& t (xt.as<file> ());
          const path& tp (t.path ());

          if (verb == 1)
            print_diag ("test", t);
          else if (verb >= 2)
            text << "cat " << tp;

          ifdstream ifs (tp);
          if (ifs.peek () != ifdstream::traits_type::eof ())
            std::cerr << ifs.rdbuf ();
          ifs.close ();

          return target_state::changed;
        }
      }}
      EOI

    $* test 2>>~%EOE%;
      %^(c\+\+|ld).*%+
      cp file{bar} -> file{foo}
      test file{foo}
      bar
      EOE

    $* clean 2>-
  }

  : rule
  :
  {
    cat <<EOI >=buildfile;
      alias{far}: alias{bar}
      alias{bar}:

      alias{~'/f(.+)/'}: alias{~'/b\1/'}
      {{ c++ 1 --

        #include <iostream>

        --

        recipe
        apply (action a, target& t) const override
        {
          const auto& mrs (t.data<regex_match_results> (a));

          return [this, mr = mrs.str (1)] (action a, const target& t)
          {
            return perform_update (a, t, mr);
          };
        }

        target_state
        perform_update (action, const target&, const string& mr) const
        {
          text << pattern->rule_name << ": " << mr;
          return target_state::changed;
        }
      }}
      EOI

    $* 2>>~%EOE%
      %^(c\+\+|ld).*%+
      <ad hoc pattern rule #1>: ar
      EOE
  }

  # Clean recipe builds if the testscript is enabled (see above for details).
  #
  -$* clean 2>-
}
