aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/test/script/parser.cxx188
-rw-r--r--build2/test/script/script4
-rw-r--r--doc/testscript.cli22
-rw-r--r--tests/common.test2
-rw-r--r--tests/function/path/testscript2
-rw-r--r--tests/test/common.test2
-rw-r--r--tests/test/script/runner/status.test2
-rw-r--r--unit-tests/test/script/parser/description.test17
8 files changed, 159 insertions, 80 deletions
diff --git a/build2/test/script/parser.cxx b/build2/test/script/parser.cxx
index 6ee1429..6054da9 100644
--- a/build2/test/script/parser.cxx
+++ b/build2/test/script/parser.cxx
@@ -111,10 +111,10 @@ namespace build2
(t = dynamic_cast<test*> (sc.back ().get ())) != nullptr &&
find_if (
su.begin (), su.end (),
- [] (const line& l)
- {
+ [] (const line& l) {
return l.type != line_type::var;
}) == su.end () &&
+
td.empty () &&
!t->desc &&
!t->if_cond_)
@@ -491,15 +491,54 @@ namespace build2
// Stop saving and get the tokens.
//
- line l {lt, replay_data ()};
+ lines ls_data;
- // Decide where it goes.
- //
- lines tests;
if (ls == nullptr)
+ ls = &ls_data;
+
+ ls->push_back (line {lt, replay_data ()});
+
+ if (lt == line_type::cmd_if || lt == line_type::cmd_ifn)
+ {
+ semi = pre_parse_if_else (t, tt, d, *ls);
+
+ // If this turned out to be scope-if, then ls is empty, semi is
+ // false, and none of the below logic applies.
+ //
+ if (ls->empty ())
+ return semi;
+ }
+
+ // Unless we were told where to put it, decide where it actually goes.
+ //
+ if (ls == &ls_data)
{
+ // First pre-check variable and variable-if: by themselves (i.e.,
+ // without a trailing semicolon) they are treated as either setup or
+ // teardown without plus/minus. Also handle illegal line types.
+ //
switch (lt)
{
+ case line_type::cmd_elif:
+ case line_type::cmd_elifn:
+ case line_type::cmd_else:
+ case line_type::cmd_end:
+ {
+ fail (ll) << lt << " without preceding 'if'";
+ }
+ case line_type::cmd_if:
+ case line_type::cmd_ifn:
+ {
+ // See if this is a variable-only command-if.
+ //
+ if (find_if (ls_data.begin (), ls_data.end (),
+ [] (const line& l) {
+ return l.type == line_type::cmd;
+ }) != ls_data.end ())
+ break;
+
+ // Fall through.
+ }
case line_type::var:
{
// If there is a semicolon after the variable then we assume
@@ -510,7 +549,13 @@ namespace build2
if (!semi)
{
if (d)
- fail (ll) << "description before setup/teardown variable";
+ {
+ if (lt == line_type::var)
+ fail (ll) << "description before setup/teardown variable";
+ else
+ fail (ll) << "description before/after setup/teardown "
+ << "variable-if";
+ }
// If we don't have any nested scopes or teardown commands,
// then we assume this is a setup, otherwise -- teardown.
@@ -518,81 +563,75 @@ namespace build2
ls = group_->scopes.empty () && group_->tdown_.empty ()
? &group_->setup_
: &group_->tdown_;
-
- break;
}
-
- // Fall through.
+ break;
}
- case line_type::cmd:
- case line_type::cmd_if:
- case line_type::cmd_ifn:
+ default:
+ break;
+ }
+
+ // If pre-check didn't change the destination, then it's a test.
+ //
+ if (ls == &ls_data)
+ {
+ switch (st)
{
- switch (st)
+ // Setup.
+ //
+ case type::plus:
{
- // Setup.
- //
- case type::plus:
- {
- if (d)
- fail (ll) << "description before setup command";
+ if (d)
+ fail (ll) << "description before setup command";
- if (!group_->scopes.empty ())
- fail (ll) << "setup command after tests";
+ if (!group_->scopes.empty ())
+ fail (ll) << "setup command after tests";
- if (!group_->tdown_.empty ())
- fail (ll) << "setup command after teardown";
+ if (!group_->tdown_.empty ())
+ fail (ll) << "setup command after teardown";
- ls = &group_->setup_;
- break;
- }
- // Teardown.
- //
- case type::minus:
- {
- if (d)
- fail (ll) << "description before teardown command";
+ ls = &group_->setup_;
+ break;
+ }
- ls = &group_->tdown_;
- break;
- }
- // Test command or variable.
+ // Teardown.
+ //
+ case type::minus:
+ {
+ if (d)
+ fail (ll) << "description before teardown command";
+
+ ls = &group_->tdown_;
+ break;
+ }
+
+ // Test command or variable.
+ //
+ default:
+ {
+ // First check that we don't have any teardown commands yet.
+ // This will detect things like variable assignments between
+ // tests.
//
- default:
+ if (!group_->tdown_.empty ())
{
- // First check that we don't have any teardown commands yet.
- // This will detect things like variable assignments between
- // tests.
- //
- if (!group_->tdown_.empty ())
- {
- location tl (
- group_->tdown_.back ().tokens.front ().location ());
-
- fail (ll) << "test after teardown" <<
- info (tl) << "last teardown line appears here";
- }
+ location tl (
+ group_->tdown_.back ().tokens.front ().location ());
- ls = &tests;
- break;
+ fail (ll) << "test after teardown" <<
+ info (tl) << "last teardown line appears here";
}
+ break;
}
- break;
- }
- case line_type::cmd_elif:
- case line_type::cmd_elifn:
- case line_type::cmd_else:
- case line_type::cmd_end:
- {
- fail (ll) << lt << " without preceding 'if'";
}
}
- }
-
- ls->push_back (move (l));
- if (lt == line_type::cmd_if || lt == line_type::cmd_ifn)
- semi = pre_parse_if_else (t, tt, d, *ls);
+ // If the destination changed, then move the data over.
+ //
+ if (ls != &ls_data)
+ ls->insert (ls->end (),
+ make_move_iterator (ls_data.begin ()),
+ make_move_iterator (ls_data.end ()));
+ }
// If this command ended with a semicolon, then the next one should
// go to the same place.
@@ -620,10 +659,9 @@ namespace build2
}
}
- // Create implicit test scope unless someone (e.g., scope if-else)
- // used them for something else.
+ // If this is a test then create implicit test scope.
//
- if (ls == &tests && !tests.empty ())
+ if (ls == &ls_data)
{
// If there is no user-supplied id, use the line number (prefixed
// with include id) as the scope id.
@@ -638,7 +676,7 @@ namespace build2
p->desc = move (d);
p->start_loc_ = ll;
- p->tests_ = move (tests);
+ p->tests_ = move (ls_data);
p->end_loc_ = get_location (t);
group_->scopes.push_back (move (p));
@@ -829,10 +867,14 @@ namespace build2
//
if (lt == line_type::cmd_end)
{
- if (d && td)
- fail (ll) << "both leading and trailing descriptions";
+ if (td)
+ {
+ if (d)
+ fail (ll) << "both leading and trailing descriptions";
+
+ d = move (td);
+ }
- d = move (td);
return semi;
}
diff --git a/build2/test/script/script b/build2/test/script/script
index 241f148..1be33bb 100644
--- a/build2/test/script/script
+++ b/build2/test/script/script
@@ -50,7 +50,9 @@ namespace build2
replay_tokens tokens;
};
- using lines = vector<line>;
+ // Most of the time we will have just one line (test command).
+ //
+ using lines = small_vector<line, 1>;
// Parse object model.
//
diff --git a/doc/testscript.cli b/doc/testscript.cli
index c09e69c..eaccd0a 100644
--- a/doc/testscript.cli
+++ b/doc/testscript.cli
@@ -740,10 +740,10 @@ description:
+(':' <text>)
setup:
- variable-line|setup-line
+ variable-like|setup-line
tdown:
- variable-line|tdown-line
+ variable-like|tdown-line
setup-line: '+' command-like
tdown-line: '-' command-like
@@ -752,6 +752,24 @@ test:
?description
+(variable-line|command-like)
+variable-like:
+ variable-line|variable-if
+
+variable-if: ('if'|'if!') command-line
+ variable-if-body
+ *variable-elif
+ ?variable-else
+ 'end'
+
+variable-elif: ('elif'|'elif!') command-line
+ variable-if-body
+
+variable-else: 'else'
+ variable-if-body
+
+variable-if-body:
+ *variable-like
+
variable-line: <variable> ('='|'+='|'=+') value-attributes? <value>
value-attributes: '[' <key-value-pairs> ']'
diff --git a/tests/common.test b/tests/common.test
index 4d4520f..a35d0f8 100644
--- a/tests/common.test
+++ b/tests/common.test
@@ -16,6 +16,6 @@ test.options += -q --buildfile -
# By default just load the buildfile.
#
-+if ($empty($test.arguments))
+if ($empty($test.arguments))
test.arguments = noop
end
diff --git a/tests/function/path/testscript b/tests/function/path/testscript
index e1f0a36..066a6c8 100644
--- a/tests/function/path/testscript
+++ b/tests/function/path/testscript
@@ -4,7 +4,7 @@
.include ../../common.test
-+if ($cxx.target.class != windows) # @@ TMP ternarry
+if ($cxx.target.class != windows) # @@ TMP ternarry
s = '/'
else
s = '\'
diff --git a/tests/test/common.test b/tests/test/common.test
index 9477359..386b16c 100644
--- a/tests/test/common.test
+++ b/tests/test/common.test
@@ -19,6 +19,6 @@ test.options += -q --buildfile -
# By default perform test.
#
-+if ($empty($test.arguments))
+if ($empty($test.arguments))
test.arguments = test
end
diff --git a/tests/test/script/runner/status.test b/tests/test/script/runner/status.test
index cf4ce1d..f743518 100644
--- a/tests/test/script/runner/status.test
+++ b/tests/test/script/runner/status.test
@@ -6,7 +6,7 @@
b += --no-column
-+if ($cxx.target.class == "windows")
+if ($cxx.target.class == "windows")
ext = ".exe"
end
diff --git a/unit-tests/test/script/parser/description.test b/unit-tests/test/script/parser/description.test
index b4ab435..16ba287 100644
--- a/unit-tests/test/script/parser/description.test
+++ b/unit-tests/test/script/parser/description.test
@@ -222,6 +222,23 @@ EOI
testscript:2:1: error: description before setup/teardown variable
EOE
+$* <<EOI 2>>EOE != 0 # illegal-var-if
+: foo
+if true
+ x = y
+end
+EOI
+testscript:2:1: error: description before/after setup/teardown variable-if
+EOE
+
+$* <<EOI 2>>EOE != 0 # illegal-var-if-after
+if true
+ x = y
+end : foo
+EOI
+testscript:1:1: error: description before/after setup/teardown variable-if
+EOE
+
$* <<EOI 2>>EOE != 0 # illegal-test
cmd1;
: foo