aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-10-24 14:55:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-11-04 09:26:35 +0200
commitaa79de0b9a1e214e923139c25b02b5313a6305a9 (patch)
tree3104cdb7f0d4008c443df43beaf70aebeb8e7ec4
parent0f7ecf29943c9d8112fff923d93eeadb99a816f3 (diff)
Implement creation/cleanup of testscript root working directory
-rw-r--r--build2/test/rule.cxx97
-rw-r--r--build2/test/script/runner.cxx2
-rw-r--r--build2/test/script/script4
-rw-r--r--build2/test/script/script.cxx21
-rw-r--r--unit-tests/test/script/parser/driver.cxx2
-rw-r--r--unit-tests/test/script/parser/scope.test4
6 files changed, 94 insertions, 36 deletions
diff --git a/build2/test/rule.cxx b/build2/test/rule.cxx
index 188cc90..36b92f2 100644
--- a/build2/test/rule.cxx
+++ b/build2/test/rule.cxx
@@ -7,6 +7,7 @@
#include <build2/scope>
#include <build2/target>
#include <build2/algorithm>
+#include <build2/filesystem>
#include <build2/diagnostics>
#include <build2/test/target>
@@ -354,33 +355,93 @@ namespace build2
target_state rule::
perform_script (action, target& t)
{
+ // Figure out whether the testscript file is called 'testscript', in
+ // which case it should be the only one.
+ //
+ optional<bool> one;
for (target* pt: t.prerequisite_targets)
{
// In case we are using the alias rule's list (see above).
//
- if (testscript* st = pt->is_a<testscript> ())
+ if (testscript* ts = pt->is_a<testscript> ())
{
- const path& sp (st->path ());
- assert (!sp.empty ()); // Should have been assigned by update.
+ bool r (ts->name == "testscript");
- if (verb)
- text << "test " << t << " with " << *st;
+ if ((r && one) || (!r && one && *one))
+ fail << "both 'testscript' and other names specified for " << t;
- try
- {
- script::script s (t, *st);
- script::concurrent_runner r;
+ one = r;
+ }
+ }
- ifdstream ifs (sp);
- script::parser p;
- p.pre_parse (ifs, sp, s);
- p.parse (sp, s, r);
- }
- catch (const io_error& e)
- {
- fail << "unable to read testscript " << sp << ": " << e.what ();
- }
+ assert (one); // We should have a testscript or we wouldn't be here.
+
+ // Calculate root working directory. It is in the out_base of the target
+ // and is called just test for dir{} targets and test-<target-name> for
+ // other targets.
+ //
+ dir_path wd (t.out_dir ());
+
+ if (t.is_a<dir> ())
+ wd /= "test";
+ else
+ wd /= "test-" + t.name;
+
+ // If this is a (potentially) multi-testscript test, then create (and
+ // cleanup) the root directory. If this is just 'testscript', then the
+ // root directory is used directly as test's working directory and it's
+ // the runner's responsibility to create and clean it up.
+ //
+ if (!*one)
+ {
+ if (!exists (wd))
+ mkdir (wd, 2);
+ else if (!empty (wd))
+ fail << "working directory " << wd << " is not empty at the "
+ << "beginning of the test";
+ }
+
+ // Run all the testscripts.
+ //
+ auto run = [&t, &wd] (testscript& ts)
+ {
+ if (verb)
+ text << "test " << t << " with " << ts;
+
+ const path& sp (ts.path ());
+ assert (!sp.empty ()); // Should have been assigned by update.
+
+ try
+ {
+ script::script s (t, ts, wd);
+ script::concurrent_runner r;
+
+ ifdstream ifs (sp);
+ script::parser p;
+ p.pre_parse (ifs, sp, s);
+ p.parse (sp, s, r);
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to read testscript " << sp << ": " << e.what ();
}
+ };
+
+ for (target* pt: t.prerequisite_targets)
+ {
+ if (testscript* ts = pt->is_a<testscript> ())
+ run (*ts);
+ }
+
+ // Cleanup.
+ //
+ if (!*one)
+ {
+ if (!empty (wd))
+ fail << "working directory " << wd << " is not empty at the "
+ << "end of the test";
+
+ rmdir (wd, 2);
}
return target_state::changed;
diff --git a/build2/test/script/runner.cxx b/build2/test/script/runner.cxx
index 7377528..55c3ffe 100644
--- a/build2/test/script/runner.cxx
+++ b/build2/test/script/runner.cxx
@@ -254,7 +254,7 @@ namespace build2
path r (sp.wd_path / path (nm));
if (ci > 0)
- r += "-" + to_string (ci);
+ r += "-" + to_string (ci + 1); // Start from first line.
return r;
};
diff --git a/build2/test/script/script b/build2/test/script/script
index 44ec7c5..f1a3f50 100644
--- a/build2/test/script/script
+++ b/build2/test/script/script
@@ -217,7 +217,9 @@ namespace build2
class script: public script_base, public group
{
public:
- script (target& test_target, testscript& script_target);
+ script (target& test_target,
+ testscript& script_target,
+ const dir_path& root_wd);
public:
target& test_target; // Target we are testing.
diff --git a/build2/test/script/script.cxx b/build2/test/script/script.cxx
index 6602518..4dd47c5 100644
--- a/build2/test/script/script.cxx
+++ b/build2/test/script/script.cxx
@@ -159,19 +159,14 @@ namespace build2
}
script::
- script (target& tt, testscript& st)
+ script (target& tt, testscript& st, const dir_path& rwd)
: group (script_id (st.path ())),
test_target (tt), script_target (st)
{
// Set the script working dir ($~) to $out_base/test/<id> (id_path
- // for root is just the id).
+ // for root is just the id which is empty if st is 'testscript').
//
- {
- auto& wd (const_cast<dir_path&> (wd_path));
- wd = tt.out_dir ();
- wd /= "test";
- wd /= id_path.string ();
- }
+ const_cast<dir_path&> (wd_path) = dir_path (rwd) /= id_path.string ();
// Unless we have the test variable set on the test or script target,
// set it at the script level to the test target's path.
@@ -180,14 +175,14 @@ namespace build2
{
value& v (assign (test_var));
- // If this is a path-based target, then we use the path. If this
- // is a directory (alias) target, then we use the directory path.
- // Otherwise, we leave it NULL expecting the testscript to set it
- // to something appropriate, if used.
+ // If this is a path-based target, then we use the path. If this is
+ // an alias target (e.g., dir{}), then we use the directory path.
+ // Otherwise, we leave it NULL expecting the testscript to set it to
+ // something appropriate, if used.
//
if (auto* p = tt.is_a<path_target> ())
v = p->path ();
- else if (tt.is_a<dir> ())
+ else if (tt.is_a<alias> ())
v = path (tt.dir.string ()); // Strip trailing slash.
}
diff --git a/unit-tests/test/script/parser/driver.cxx b/unit-tests/test/script/parser/driver.cxx
index 09fd6f5..4fd0489 100644
--- a/unit-tests/test/script/parser/driver.cxx
+++ b/unit-tests/test/script/parser/driver.cxx
@@ -120,7 +120,7 @@ namespace build2
// Parse and run.
//
- script s (tt, st);
+ script s (tt, st, dir_path (work) /= "test-driver");
print_runner r (scope);
parser p;
diff --git a/unit-tests/test/script/parser/scope.test b/unit-tests/test/script/parser/scope.test
index 7749b3d..4e358f3 100644
--- a/unit-tests/test/script/parser/scope.test
+++ b/unit-tests/test/script/parser/scope.test
@@ -2,12 +2,12 @@ $* testscript <'cmd $@' >"cmd 1" # id-testscript
$* foo.test <'cmd $@' >"cmd foo/1" # id
wd = [dir_path] $~;
-wd += test;
+wd += test-driver;
wd += 1;
$* testscript <'cmd $~' >"cmd $wd" # wd-testscript
wd = [dir_path] $~;
-wd += test;
+wd += test-driver;
wd += foo;
wd += 1;
$* foo.test <'cmd $~' >"cmd $wd" # wd