aboutsummaryrefslogtreecommitdiff
path: root/build2/test/script
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-10-21 17:07:18 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-11-04 09:26:34 +0200
commitd9b26553b67e87dd45b652dd91eaac782fdf91f9 (patch)
treea42f2e8d4d6bf2e6232861b57d262d2cf8cc0a33 /build2/test/script
parenta36a5042a35ddf5e8e32dd351168d9e71cd761f2 (diff)
Add support for testscript scope id, working directory
Diffstat (limited to 'build2/test/script')
-rw-r--r--build2/test/script/lexer.cxx4
-rw-r--r--build2/test/script/parser.cxx14
-rw-r--r--build2/test/script/runner4
-rw-r--r--build2/test/script/runner.cxx2
-rw-r--r--build2/test/script/script50
-rw-r--r--build2/test/script/script.cxx73
6 files changed, 108 insertions, 39 deletions
diff --git a/build2/test/script/lexer.cxx b/build2/test/script/lexer.cxx
index 01c93a4..5061a1d 100644
--- a/build2/test/script/lexer.cxx
+++ b/build2/test/script/lexer.cxx
@@ -284,14 +284,14 @@ namespace build2
lexer_mode m (st.mode);
// Customized implementation that handles special variable names ($*,
- // $~, $NNN).
+ // $NN, $~, $@).
//
if (m != lexer_mode::variable)
return base_lexer::word (st, sep);
xchar c (peek ());
- if (c != '*' && c != '~' && !digit (c))
+ if (c != '*' && c != '~' && c != '@' && !digit (c))
return base_lexer::word (st, sep);
uint64_t ln (c.line), cn (c.column);
diff --git a/build2/test/script/parser.cxx b/build2/test/script/parser.cxx
index 756761f..a3860c4 100644
--- a/build2/test/script/parser.cxx
+++ b/build2/test/script/parser.cxx
@@ -79,6 +79,7 @@ namespace build2
if (tt == type::eos)
break;
+ const location ll (get_location (t));
line_type lt (pre_parse_script_line (t, tt));
assert (tt == type::newline);
@@ -98,11 +99,11 @@ namespace build2
}
case line_type::test:
{
- // Create implicit test scope.
+ // Create implicit test scope. Use line number as the scope id.
//
group_->scopes.push_back (
unique_ptr<test> (
- (test_ = new test (*group_))));
+ (test_ = new test (to_string (ll.line), *group_))));
ls = &test_->tests;
@@ -740,7 +741,7 @@ namespace build2
// Now that we have all the pieces, run the command.
//
if (!pre_parse_)
- runner_->run (c, li, ll);
+ runner_->run (*scope_, c, li, ll);
}
command_exit parser::
@@ -847,7 +848,8 @@ namespace build2
if (!qual.empty ())
fail (loc) << "qualified variable name";
- // @@ MT: will need RW mutex on var_pool.
+ // @@ MT: will need RW mutex on var_pool. Or maybe if it's not there
+ // then it can't possibly be found? Still will be setting variables.
//
if (name != "*" && !digits (name))
return scope_->find (script_->var_pool.insert (move (name)));
@@ -861,6 +863,10 @@ namespace build2
// we don't know which $NN vars will be looked up from inside.
// Could we collect all the variable names during the pre-parse
// stage? They could be computed.
+ //
+ // Or we could set all the non-NULL $NN (i.e., based on the number
+ // of elements in $*).
+ //
// In both cases first thing we do is lookup $*. It should always be
// defined since we set it on the script's root scope.
diff --git a/build2/test/script/runner b/build2/test/script/runner
index 57e506f..e2cffcf 100644
--- a/build2/test/script/runner
+++ b/build2/test/script/runner
@@ -31,14 +31,14 @@ namespace build2
// It can be used in diagnostics.
//
virtual void
- run (const command&, size_t index, const location&) = 0;
+ run (const scope&, const command&, size_t index, const location&) = 0;
};
class concurrent_runner: public runner
{
public:
virtual void
- run (const command&, size_t, const location&) override;
+ run (const scope&, const command&, size_t, const location&) override;
};
}
}
diff --git a/build2/test/script/runner.cxx b/build2/test/script/runner.cxx
index abd1ef3..7844119 100644
--- a/build2/test/script/runner.cxx
+++ b/build2/test/script/runner.cxx
@@ -250,7 +250,7 @@ namespace build2
}
void concurrent_runner::
- run (const command& c, size_t ci, const location& cl)
+ run (const scope&, const command& c, size_t ci, const location& cl)
{
if (verb >= 3)
text << c;
diff --git a/build2/test/script/script b/build2/test/script/script
index 860e5d4..7fbe949 100644
--- a/build2/test/script/script
+++ b/build2/test/script/script
@@ -103,10 +103,21 @@ namespace build2
ostream&
operator<< (ostream&, const command&);
+ class script;
+
class scope
{
public:
- scope* parent; // NULL for the root (script) scope.
+ scope* const parent; // NULL for the root (script) scope.
+ script* const root; // Self for the root (script) scope.
+
+ // Note that if we pass the variable name as a string, then it will
+ // be looked up in the wrong pool.
+ //
+ variable_map vars;
+
+ const path& id_path; // Id path ($@, relative in POSIX form).
+ const dir_path& wd_path; // Working dir ($~, absolute and normalized).
lines setup;
lines tdown;
@@ -114,11 +125,6 @@ namespace build2
// Variables.
//
public:
- // Note that if we pass the variable name as a string, then it will
- // be looked up in the wrong pool.
- //
- variable_map vars;
-
// Lookup the variable starting from this scope, continuing with outer
// scopes, then the target being tested, then the testscript target,
// and then outer buildfile scopes (including testscript-type/pattern
@@ -148,8 +154,7 @@ namespace build2
~scope () = default;
protected:
- scope (scope* p): parent (p) {}
- scope (): parent (nullptr) {} // For the root (script) scope.
+ scope (const string& id, scope* parent);
};
class group: public scope
@@ -158,10 +163,10 @@ namespace build2
vector<unique_ptr<scope>> scopes;
public:
- group (group& p): scope (&p) {}
+ group (const string& id, group& p): scope (id, &p) {}
protected:
- group (): scope (nullptr) {} // For the root (script) scope.
+ group (const string& id): scope (id, nullptr) {} // For root.
};
class test: public scope
@@ -170,17 +175,13 @@ namespace build2
lines tests;
public:
- test (group& p): scope (&p) {}
+ test (const string& id, group& p): scope (id, &p) {}
};
- class script: public group
+ class script_base // Make sure certain things are initialized early.
{
- public:
- script (target& test_target, testscript& script_target);
-
- public:
- target& test_target; // Target we are testing.
- testscript& script_target; // Target of the testscript file.
+ protected:
+ script_base ();
public:
variable_pool var_pool;
@@ -190,7 +191,18 @@ namespace build2
const variable& args_var; // test.arguments
const variable& cmd_var; // $*
- const variable& cwd_var; // $~
+ const variable& wd_var; // $~
+ const variable& id_var; // $@
+ };
+
+ class script: public script_base, public group
+ {
+ public:
+ script (target& test_target, testscript& script_target);
+
+ public:
+ target& test_target; // Target we are testing.
+ testscript& script_target; // Target of the testscript file.
};
}
}
diff --git a/build2/test/script/script.cxx b/build2/test/script/script.cxx
index 5931d3f..6602518 100644
--- a/build2/test/script/script.cxx
+++ b/build2/test/script/script.cxx
@@ -102,11 +102,38 @@ namespace build2
}
}
- script::
- script (target& tt, testscript& st)
- : test_target (tt), script_target (st),
+ scope::
+ scope (const string& id, scope* p)
+ : parent (p),
+ root (p != nullptr ? p->root : static_cast<script*> (this)),
+ id_path (cast<path> (assign (root->id_var) = path ())),
+ wd_path (cast<dir_path> (assign (root->wd_var) = dir_path ()))
+
+ {
+ // Construct the id_path as a string to ensure POSIX form. In fact,
+ // the only reason we keep it as a path is to be able to easily get id
+ // by calling leaf().
+ //
+ {
+ string s (p != nullptr ? p->id_path.string () : string ());
+
+ if (!s.empty () && !id.empty ())
+ s += '/';
- // Enter the test* variables with the same variable types as in
+ s += id;
+ const_cast<path&> (id_path) = path (move (s));
+ }
+
+ // Calculate the working directory path unless this is the root scope
+ // (handled in an ad hoc way).
+ //
+ if (p != nullptr)
+ const_cast<dir_path&> (wd_path) = dir_path (p->wd_path) /= id;
+ }
+
+ script_base::
+ script_base ()
+ : // Enter the test* variables with the same variable types as in
// buildfiles.
//
test_var (var_pool.insert<path> ("test")),
@@ -114,8 +141,38 @@ namespace build2
args_var (var_pool.insert<strings> ("test.arguments")),
cmd_var (var_pool.insert<strings> ("*")),
- cwd_var (var_pool.insert<dir_path> ("~"))
+ wd_var (var_pool.insert<dir_path> ("~")),
+ id_var (var_pool.insert<path> ("@")) {}
+
+ static inline string
+ script_id (const path& p)
+ {
+ string r (p.leaf ().string ());
+
+ if (r == "testscript")
+ return string ();
+
+ size_t n (path::traits::find_extension (r));
+ assert (n != string::npos);
+ r.resize (n);
+ return r;
+ }
+
+ script::
+ script (target& tt, testscript& st)
+ : 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).
+ //
+ {
+ auto& wd (const_cast<dir_path&> (wd_path));
+ wd = tt.out_dir ();
+ wd /= "test";
+ wd /= 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.
//
@@ -138,12 +195,6 @@ namespace build2
// on first access.
//
assign (cmd_var) = nullptr;
-
- // Set the script CWD ($~) which is the $out_base/<script-name>.
- //
- // @@ This will conflict for 'testscript'!
- //
- assign (cwd_var) = dir_path (tt.out_dir ()) /= st.name;
}
lookup scope::