aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-08-29 15:41:07 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-08-29 15:41:07 +0200
commit4f841757b84ddb2cf844252633dc2403569aa066 (patch)
tree0fe5bd6e89682a535e898d64adc2f27590119e63
parent2abd895682ec8707f30fc6babbf3787e00a8c280 (diff)
Add unit-tests option to bdep-new
If specified (-t exe,unit-tests or -t lib,unit-tests) then generate build infrastructure for unit testing.
-rw-r--r--bdep/new.cli12
-rw-r--r--bdep/new.cxx330
-rw-r--r--build/root.build5
-rw-r--r--tests/ci.test2
-rw-r--r--tests/config.test2
-rw-r--r--tests/fetch.test2
-rw-r--r--tests/init.test2
-rw-r--r--tests/new.test73
-rw-r--r--tests/publish.test2
-rw-r--r--tests/status.test2
-rw-r--r--tests/sync.test2
-rw-r--r--tests/test.test2
-rw-r--r--tests/update.test2
13 files changed, 309 insertions, 129 deletions
diff --git a/bdep/new.cli b/bdep/new.cli
index d7e3ed0..688f14c 100644
--- a/bdep/new.cli
+++ b/bdep/new.cli
@@ -76,6 +76,8 @@ namespace bdep
project options:
\cb{no-tests} \- Don't add support for functional/integration testing.
+
+ \cb{unit-tests} \- Add support for unit testing.
|
\li|\cb{lib}
@@ -84,14 +86,16 @@ namespace bdep
options:
\cb{no-tests} \- Don't add support for functional/integration testing.
- |
+
+ \cb{unit-tests} \- Add support for unit testing.
+ |
\li|\cb{bare}
A project without any source code. Recognized bare project options:
- \cb{no-tests} \- Don't add support for functional/integration testing.
- |
+ \cb{no-tests} \- Don't add support for testing.
+ |
\li|\cb{empty}
@@ -142,11 +146,13 @@ namespace bdep
class cmd_new_exe_options
{
bool no-tests;
+ bool unit-tests;
};
class cmd_new_lib_options
{
bool no-tests;
+ bool unit-tests;
};
class cmd_new_bare_options
diff --git a/bdep/new.cxx b/bdep/new.cxx
index 45c3234..264cd47 100644
--- a/bdep/new.cxx
+++ b/bdep/new.cxx
@@ -58,10 +58,13 @@ namespace bdep
//
const type& t (o.type ());
- bool tests (t == type::exe ? !t.exe_opt.no_tests () :
+ bool itest (t == type::exe ? !t.exe_opt.no_tests () :
t == type::lib ? !t.lib_opt.no_tests () :
t == type::bare ? !t.bare_opt.no_tests () : false);
+ bool utest (t == type::exe ? t.exe_opt.unit_tests () :
+ t == type::lib ? t.lib_opt.unit_tests () : false);
+
// Validate language options.
//
const lang& l (o.lang ());
@@ -169,7 +172,6 @@ namespace bdep
}
}
-
dir_path out; // Project/package output directory.
dir_path prj; // Project.
optional<dir_path> pkg; // Package relative to its project root.
@@ -403,7 +405,7 @@ namespace bdep
os << endl
<< "using version" << endl
<< "using config" << endl;
- if (tests)
+ if (itest || utest)
os << "using test" << endl;
os << "using install" << endl
<< "using dist" << endl;
@@ -414,10 +416,20 @@ namespace bdep
// Note: see also tests/build/root.build below.
//
os.open (f = bd / "root.build");
+
+ const char* x (nullptr); // Language module/source target type.
+ const char* h (nullptr); // Header target type.
+ const char* hs (nullptr); // All header target types.
+ string es; // Source file extension suffix (pp, xx).
+
switch (l)
{
case lang::c:
{
+ x = "c";
+ h = "h";
+ hs = "h";
+
// @@ TODO: 'latest' in c.std.
//
os //<< "c.std = latest" << endl
@@ -430,24 +442,29 @@ namespace bdep
}
case lang::cxx:
{
- const char* s (l.cxx_opt.cpp () ? "pp" : "xx");
+ x = "cxx";
+ h = "hxx";
+ hs = "hxx ixx txx";
+ es = l.cxx_opt.cpp () ? "pp" : "xx";
os << "cxx.std = latest" << endl
<< endl
<< "using cxx" << endl
<< endl
- << "hxx{*}: extension = h" << s << endl
- << "ixx{*}: extension = i" << s << endl
- << "txx{*}: extension = t" << s << endl
- << "cxx{*}: extension = c" << s << endl;
+ << "hxx{*}: extension = h" << es << endl
+ << "ixx{*}: extension = i" << es << endl
+ << "txx{*}: extension = t" << es << endl
+ << "cxx{*}: extension = c" << es << endl;
break;
}
}
- if (tests)
+
+ if ((itest || utest) && x != nullptr)
os << endl
<< "# The test target for cross-testing (running tests under Wine, etc)." << endl
<< "#" << endl
- << "test.target = $cxx.target" << endl;
+ << "test.target = $" << x << ".target" << endl;
+
os.close ();
// build/.gitignore
@@ -465,7 +482,7 @@ namespace bdep
//
os.open (f = out / "buildfile");
os << "./: {*/ -build/} manifest" << endl;
- if (tests && t == type::lib) // Have tests/ subproject.
+ if (itest && t == type::lib) // Have tests/ subproject.
os << endl
<< "# Don't install tests." << endl
<< "#" << endl
@@ -510,11 +527,9 @@ namespace bdep
}
case lang::cxx:
{
- string x (l.cxx_opt.cpp () ? "pp" : "xx");
-
// <base>/<stem>.c(xx|pp)
//
- os.open (f = sd / s + ".c" + x);
+ os.open (f = sd / s + ".c" + es);
os << "#include <iostream>" << endl
<< endl
<< "int main (int argc, char* argv[])" << endl
@@ -538,30 +553,36 @@ namespace bdep
// <base>/buildfile
//
os.open (f = sd / "buildfile");
- os << "libs =" << endl
- << "#import libs += libhello%lib{hello}" << endl
- << endl;
-
- const char* x (nullptr); // Language module.
- switch (l)
- {
- case lang::c:
- {
- os << "exe{" << s << "}: {h c}{**} $libs" <<
- (tests ? " testscript" : "") << endl;
-
- x = "c";
- break;
- }
- case lang::cxx:
- {
- os << "exe{" << s << "}: {hxx ixx txx cxx}{**} $libs" <<
- (tests ? " testscript" : "") << endl;
+ os << "libs =" << endl
+ << "#import libs += libhello%lib{hello}" << endl
+ << endl;
- x = "cxx";
- break;
- }
- }
+ if (!utest)
+ os << "exe{" << s << "}: " <<
+ "{" << hs << ' ' << x << "}{**} " <<
+ "$libs" <<
+ (itest ? " testscript" : "") << endl;
+ else
+ os << "./: exe{" << s << "}" << endl
+ << "exe{" << s << "}: libue{" << s << "}" <<
+ (itest ? " testscript" : "") << endl
+ << "libue{" << s << "}: " <<
+ "{" << hs << ' ' << x << "}{** -**.test...} $libs" << endl
+ << endl
+ << "# Unit tests." << endl
+ << "#" << endl
+ << "exe{*.test}: test = true" << endl
+ << "exe{*.test}: install = false" << endl
+ << endl
+ << "for t: " << x << "{**.test...}" << endl
+ << "{" << endl
+ << " d = $directory($t)" << endl
+ << " n = $name($t)..." << endl
+ << endl
+ << " ./: $d/exe{$n}" << endl
+ << " $d/exe{$n}: $t $d/{" << hs << "}{+$n} $d/test{+$n}" << endl
+ << " $d/exe{$n}: libue{" << s << "}: bin.whole = false"<< endl
+ << "}" << endl;
os << endl
<< x << ".poptions =+ \"-I$out_root\" \"-I$src_root\"" << endl;
@@ -573,30 +594,76 @@ namespace bdep
{
os.open (f = sd / ".gitignore");
os << s << endl;
- if (tests)
+ if (utest)
+ os << "*.test" << endl;
+ if (itest || utest)
os << endl
<< "# Testscript output directory (can be symlink)." << endl
- << "#" << endl
- << "test-" << s << endl;
+ << "#" << endl;
+ if (itest)
+ os << "test-" << s << endl;
+ if (utest)
+ os << "test-*.test" << endl;
os.close ();
}
// <base>/testscript
//
- if (!tests)
- break;
+ if (itest)
+ {
+ os.open (f = sd / "testscript");
+ os << ": basics" << endl
+ << ":" << endl
+ << "$* 'World' >'Hello, World!'" << endl
+ << endl
+ << ": missing-name" << endl
+ << ":" << endl
+ << "$* 2>>EOE != 0" << endl
+ << "error: missing name" << endl
+ << "EOE" << endl;
+ os.close ();
+ }
- os.open (f = sd / "testscript");
- os << ": basics" << endl
- << ":" << endl
- << "$* 'World' >'Hello, World!'" << endl
- << endl
- << ": missing-name" << endl
- << ":" << endl
- << "$* 2>>EOE != 0" << endl
- << "error: missing name" << endl
- << "EOE" << endl;
- os.close ();
+ // <base>/<stem>.test.*
+ //
+ if (utest)
+ {
+ switch (l)
+ {
+ case lang::c:
+ {
+ // <base>/<stem>.test.c
+ //
+ os.open (f = sd / s + ".test.c");
+ os << "#include <stdio.h>" << endl
+ << "#include <assert.h>" << endl
+ << endl
+ << "int main ()" << endl
+ << "{" << endl
+ << " return 0;" << endl
+ << "}" << endl;
+ os.close ();
+
+ break;
+ }
+ case lang::cxx:
+ {
+ // <base>/<stem>.test.c(xx|pp)
+ //
+ os.open (f = sd / s + ".test.c" + es);
+ os << "#include <cassert>" << endl
+ << "#include <iostream>" << endl
+ << endl
+ << "int main ()" << endl
+ << "{" << endl
+ << endl
+ << "}" << endl;
+ os.close ();
+
+ break;
+ }
+ }
+ }
break;
}
@@ -662,11 +729,9 @@ namespace bdep
}
case lang::cxx:
{
- string x (l.cxx_opt.cpp () ? "pp" : "xx");
-
- hdr = s + ".h" + x;
- exp = "export.h" + x;
- ver = "version.h" + x;
+ hdr = s + ".h" + es;
+ exp = "export.h" + es;
+ ver = "version.h" + es;
// <stem>.h(xx|pp)
//
@@ -691,7 +756,7 @@ namespace bdep
// <stem>.c(xx|pp)
//
- os.open (f = sd / s + ".c" + x);
+ os.open (f = sd / s + ".c" + es);
os << "#include <" << b << "/" << hdr << ">" << endl
<< endl
<< "#include <ostream>" << endl
@@ -804,30 +869,32 @@ namespace bdep
<< "#import imp_libs += libhello%lib{hello}" << endl
<< endl;
- const char* x (nullptr); // Language module.
- const char* h (nullptr); // Header target type.
- const char* hs (nullptr); // All header target types.
- switch (l)
- {
- case lang::c:
- {
- os << "lib{" << s << "}: {h c}{** -version} h{version}" << endl;
-
- x = "c";
- h = "h";
- hs = "h";
- break;
- }
- case lang::cxx:
- {
- os << "lib{" << s << "}: {hxx ixx txx cxx}{** -version} hxx{version} $imp_libs $int_libs" << endl;
-
- x = "cxx";
- h = "hxx";
- hs = "hxx ixx txx";
- break;
- }
- }
+ if (!utest)
+ os << "lib{" << s << "}: " <<
+ "{" << hs << ' ' << x << "}{** -version} " <<
+ h << "{version} $imp_libs $int_libs" << endl;
+ else
+ os << "./: lib{" << s << "}" << endl
+ << "lib{" << s << "}: libul{" << s << "}" << endl
+ << "libul{" << s << "}: " <<
+ "{" << hs << ' ' << x << "}{** -version -**.test...} " <<
+ h << "{version} \\" << endl
+ << " $imp_libs $int_libs" << endl
+ << endl
+ << "# Unit tests." << endl
+ << "#" << endl
+ << "exe{*.test}: test = true" << endl
+ << "exe{*.test}: install = false" << endl
+ << endl
+ << "for t: " << x << "{**.test...}" << endl
+ << "{" << endl
+ << " d = $directory($t)" << endl
+ << " n = $name($t)..." << endl
+ << endl
+ << " ./: $d/exe{$n}" << endl
+ << " $d/exe{$n}: $t $d/{" << hs << "}{+$n} $d/test{+$n}" << endl
+ << " $d/exe{$n}: libul{" << s << "}: bin.whole = false"<< endl
+ << "}" << endl;
os << endl
<< "# Include the generated version header into the distribution (so that we don't" << endl
@@ -869,12 +936,64 @@ namespace bdep
if (vc == vcs::git)
{
os.open (f = sd / ".gitignore");
- os << "# Generated version header." << endl
- << "#" << endl
- << ver << endl;
+ os << "# Generated version header." << endl
+ << "#" << endl
+ << ver << endl;
+ if (utest)
+ os << endl
+ << "# Unit test executables and Testscript output directories" << endl
+ << "# (can be symlinks)." << endl
+ << "#" << endl
+ << "*.test" << endl
+ << "test-*.test" << endl;
os.close ();
}
+ // <base>/<stem>.test.*
+ //
+ if (utest)
+ {
+ switch (l)
+ {
+ case lang::c:
+ {
+ // <base>/<stem>.test.c
+ //
+ os.open (f = sd / s + ".test.c");
+ os << "#include <stdio.h>" << endl
+ << "#include <assert.h>" << endl
+ << endl
+ << "#include <" << b << "/" << hdr << ">" << endl
+ << endl
+ << "int main ()" << endl
+ << "{" << endl
+ << " return 0;" << endl
+ << "}" << endl;
+ os.close ();
+
+ break;
+ }
+ case lang::cxx:
+ {
+ // <base>/<stem>.test.c(xx|pp)
+ //
+ os.open (f = sd / s + ".test.c" + es);
+ os << "#include <cassert>" << endl
+ << "#include <iostream>" << endl
+ << endl
+ << "#include <" << b << "/" << hdr << ">" << endl
+ << endl
+ << "int main ()" << endl
+ << "{" << endl
+ << endl
+ << "}" << endl;
+ os.close ();
+
+ break;
+ }
+ }
+ }
+
// build/export.build
//
os.open (f = bd / "export.build");
@@ -888,7 +1007,7 @@ namespace bdep
// tests/ (tests subproject).
//
- if (!tests)
+ if (!itest)
break;
dir_path td (dir_path (out) /= "tests");
@@ -928,16 +1047,14 @@ namespace bdep
}
case lang::cxx:
{
- const char* s (l.cxx_opt.cpp () ? "pp" : "xx");
-
os << "cxx.std = latest" << endl
<< endl
<< "using cxx" << endl
<< endl
- << "hxx{*}: extension = h" << s << endl
- << "ixx{*}: extension = i" << s << endl
- << "txx{*}: extension = t" << s << endl
- << "cxx{*}: extension = c" << s << endl;
+ << "hxx{*}: extension = h" << es << endl
+ << "ixx{*}: extension = i" << es << endl
+ << "txx{*}: extension = t" << es << endl
+ << "cxx{*}: extension = c" << es << endl;
break;
}
}
@@ -948,7 +1065,7 @@ namespace bdep
<< endl
<< "# The test target for cross-testing (running tests under Wine, etc)." << endl
<< "#" << endl
- << "test.target = $cxx.target" << endl;
+ << "test.target = $" << x << ".target" << endl;
os.close ();
// tests/build/.gitignore
@@ -1033,11 +1150,9 @@ namespace bdep
}
case lang::cxx:
{
- string x (l.cxx_opt.cpp () ? "pp" : "xx");
-
// tests/basics/driver.c(xx|pp)
//
- os.open (f = td / "driver.c" + x);
+ os.open (f = td / "driver.c" + es);
os << "#include <cassert>" << endl
<< "#include <sstream>" << endl
<< "#include <stdexcept>" << endl
@@ -1081,23 +1196,10 @@ namespace bdep
//
os.open (f = td / "buildfile");
os << "import libs = " << n << "%lib{" << s << "}" << endl
- << endl;
-
- switch (l)
- {
- case lang::c:
- {
- os << "exe{driver}: {h c}{**} $libs" << endl;
- break;
- }
- case lang::cxx:
- {
- os << "exe{driver}: {hxx ixx txx cxx}{**} $libs" << endl;
- break;
- }
- }
- //os << endl
- // << x << ".poptions =+ \"-I$out_root\" \"-I$src_root\"" << endl;
+ << endl
+ << "exe{driver}: {" << hs << ' ' << x << "}{**} $libs test{**}" << endl;
+ // << endl
+ // << x << ".poptions =+ \"-I$out_root\" \"-I$src_root\"" << endl;
os.close ();
break;
diff --git a/build/root.build b/build/root.build
index 20ec18b..af83c1d 100644
--- a/build/root.build
+++ b/build/root.build
@@ -13,6 +13,11 @@ cxx{*}: extension = cxx
cxx.poptions =+ "-I$out_root" "-I$src_root"
+# While we don't have any C sources to compile we do run C tests (bdep-new)
+# which need the path to the C compiler.
+#
+using c
+
# Load the cli module but only if it's available. This way a distribution
# that includes pre-generated files can be built without installing cli.
# This is also the reason why we need to explicitly spell out individual
diff --git a/tests/ci.test b/tests/ci.test
index 85155de..ed6f0c0 100644
--- a/tests/ci.test
+++ b/tests/ci.test
@@ -50,7 +50,7 @@ repository='http://example.com/prj.git'
test.arguments += --yes --repository "$repository" --server "$server" \
--simulate 'success'
-cxx = cc "config.cxx=$config.cxx"
+cxx = cc config.cxx="$recall($cxx.path)"
new += 2>!
init += $cxx -d prj 2>! &prj/**/bootstrap/***
diff --git a/tests/config.test b/tests/config.test
index 3dcd9f6..0500686 100644
--- a/tests/config.test
+++ b/tests/config.test
@@ -7,7 +7,7 @@
.include common.test project.test
-cxx = cc "config.cxx=$config.cxx"
+cxx = cc config.cxx="$recall($cxx.path)"
status += -d prj
init += -d prj
diff --git a/tests/fetch.test b/tests/fetch.test
index 0d0c1bc..d97bf63 100644
--- a/tests/fetch.test
+++ b/tests/fetch.test
@@ -4,7 +4,7 @@
.include common.test project.test
-cxx = cc "config.cxx=$config.cxx"
+cxx = cc config.cxx="$recall($cxx.path)"
new += 2>!
init += $cxx -d prj 2>!
diff --git a/tests/init.test b/tests/init.test
index 28f66e2..6214985 100644
--- a/tests/init.test
+++ b/tests/init.test
@@ -7,7 +7,7 @@
.include common.test project.test
-cxx = cc "config.cxx=$config.cxx"
+cxx = cc config.cxx="$recall($cxx.path)"
status += -d prj
deinit += -d prj
diff --git a/tests/new.test b/tests/new.test
index 6ae37e4..ee53668 100644
--- a/tests/new.test
+++ b/tests/new.test
@@ -8,7 +8,8 @@
#
test.arguments += --no-checks
-cxx = "config.cxx=$config.cxx"
+c = config.c="$recall($c.path)"
+cxx = config.cxx="$recall($cxx.path)"
status += -d prj
@@ -21,7 +22,7 @@ status += -d prj
: exe
{
- $* --no-amalgamation -t exe -l c++ prj-foo 2>>/"EOE" &prj-foo/***;
+ $* -t exe -l c++ prj-foo 2>>/"EOE" &prj-foo/***;
created new executable project prj-foo in $~/prj-foo/
EOE
@@ -30,9 +31,20 @@ status += -d prj
EOE
}
+ : exe-c
+ {
+ $* -t exe -l c prj-foo 2>>/"EOE" &prj-foo/***;
+ created new executable project prj-foo in $~/prj-foo/
+ EOE
+
+ $build prj-foo/ $c 2>>~%EOE%
+ %(c|ld) .+%{2}
+ EOE
+ }
+
: lib
{
- $* --no-amalgamation -t lib -l c++ libprj-foo 2>>/"EOE" &libprj-foo/***;
+ $* -t lib -l c++ libprj-foo 2>>/"EOE" &libprj-foo/***;
created new library project libprj-foo in $~/libprj-foo/
EOE
@@ -41,6 +53,61 @@ status += -d prj
EOE
}
+ : lib-c
+ {
+ $* -t lib -l c libprj-foo 2>>/"EOE" &libprj-foo/***;
+ created new library project libprj-foo in $~/libprj-foo/
+ EOE
+
+ $build libprj-foo/ $c 2>>~%EOE%
+ %(version\.in|c|ar|ld) .+%{7}
+ EOE
+ }
+
+ : exe-unit-tests
+ {
+ $* -t exe,unit-tests -l c++ foo 2>>/"EOE" &foo/***;
+ created new executable project foo in $~/foo/
+ EOE
+
+ $build foo/ $cxx 2>>~%EOE%
+ %(c\+\+|ld|ar) .+%{5}
+ EOE
+ }
+
+ : exe-c-unit-tests
+ {
+ $* -t exe,unit-tests -l c foo 2>>/"EOE" &foo/***;
+ created new executable project foo in $~/foo/
+ EOE
+
+ $build foo/ $c 2>>~%EOE%
+ %(c|ld|ar) .+%{5}
+ EOE
+ }
+
+ : lib-unit-tests
+ {
+ $* -t lib,unit-tests -l c++ libfoo 2>>/"EOE" &libfoo/***;
+ created new library project libfoo in $~/libfoo/
+ EOE
+
+ $build libfoo/ $cxx 2>>~%EOE%
+ %(version\.in|c\+\+|ar|ld) .+%{11}
+ EOE
+ }
+
+ : lib-c-unit-tests
+ {
+ $* -t lib,unit-tests -l c libfoo 2>>/"EOE" &libfoo/***;
+ created new library project libfoo in $~/libfoo/
+ EOE
+
+ $build libfoo/ $c 2>>~%EOE%
+ %(version\.in|c|ar|ld) .+%{11}
+ EOE
+ }
+
: pkg
:
{
diff --git a/tests/publish.test b/tests/publish.test
index ba88e9a..0861931 100644
--- a/tests/publish.test
+++ b/tests/publish.test
@@ -30,7 +30,7 @@ end
test.arguments += --repository "$repository" --yes \
--author-name user --author-email user@example.com
-cxx = cc "config.cxx=$config.cxx"
+cxx = cc config.cxx="$recall($cxx.path)"
new += 2>!
init += $cxx -d prj 2>! &prj/**/bootstrap/***
diff --git a/tests/status.test b/tests/status.test
index 676dac0..2d60af5 100644
--- a/tests/status.test
+++ b/tests/status.test
@@ -4,7 +4,7 @@
.include common.test project.test
-cxx = cc "config.cxx=$config.cxx"
+cxx = cc config.cxx="$recall($cxx.path)"
new += 2>!
init += $cxx -d prj 2>!
diff --git a/tests/sync.test b/tests/sync.test
index b297990..4872f11 100644
--- a/tests/sync.test
+++ b/tests/sync.test
@@ -4,7 +4,7 @@
.include common.test
-cxx = cc "config.cxx=$config.cxx"
+cxx = cc config.cxx="$recall($cxx.path)"
new += 2>!
init += $cxx -d prj 2>!
diff --git a/tests/test.test b/tests/test.test
index 4ee43e0..667ee7a 100644
--- a/tests/test.test
+++ b/tests/test.test
@@ -4,7 +4,7 @@
.include common.test
-cxx = cc "config.cxx=$config.cxx"
+cxx = cc config.cxx="$recall($cxx.path)"
new += 2>!
init += cc "config.cxx=$config.cxx" -d prj 2>!
diff --git a/tests/update.test b/tests/update.test
index ed4bbd2..12be96e 100644
--- a/tests/update.test
+++ b/tests/update.test
@@ -7,7 +7,7 @@
.include common.test
-cxx = cc "config.cxx=$config.cxx"
+cxx = cc config.cxx="$recall($cxx.path)"
new += 2>!
init += $cxx -d prj 2>!