Update kyua-cli to 0.7:

The major reason for this update is to support the just-imported lutok-0.3
and, in turn, support the eventual update of the in-tree lua to 5.2.

Changes:

Experimental version released on October 18th, 2013.

* Made failures from testers more resilent.  If a tester fails, the
  corresponding test case will be marked as broken instead of causing
  kyua to exit.

* Added the '--results-filter' option to the 'report-html' command and
  set its default value to skip passed results from HTML reports.  This
  is to keep these reports more succint and to avoid generating tons of
  detail files that will be, in general, useless.

* Switched to use Lutok 0.3 to gain compatibility with Lua 5.2.

* Issue 69: Cope with the lack of AM_PROG_AR in configure.ac, which
  first appeared in Automake 1.11.2.  Fixes a problem in Ubuntu 10.04
  LTS, which appears stuck in 1.11.1.
This commit is contained in:
jmmv 2013-10-18 23:40:04 +00:00
parent 1b8cab4730
commit f39f9c9b2b
50 changed files with 707 additions and 216 deletions

View File

@ -1,3 +1,24 @@
Changes in version 0.7
======================
Experimental version released on October 18th, 2013.
* Made failures from testers more resilent. If a tester fails, the
corresponding test case will be marked as broken instead of causing
kyua to exit.
* Added the '--results-filter' option to the 'report-html' command and
set its default value to skip passed results from HTML reports. This
is to keep these reports more succint and to avoid generating tons of
detail files that will be, in general, useless.
* Switched to use Lutok 0.3 to gain compatibility with Lua 5.2.
* Issue 69: Cope with the lack of AM_PROG_AR in configure.ac, which
first appeared in Automake 1.11.2. Fixes a problem in Ubuntu 10.04
LTS, which appears stuck in 1.11.1.
Changes in version 0.6
======================
@ -52,8 +73,8 @@ Experimental version released on February 22nd, 2013.
* Removed the GDB build-time configuration variable. This is now part
of the kyua-testers package.
* Rewrote the Kyuafile parsing code in C++, which results in a much
simpler implementation. As a side-effect, this gets rid of the
* Issue 31: Rewrote the Kyuafile parsing code in C++, which results in
a much simpler implementation. As a side-effect, this gets rid of the
external Lua files required by 'kyua', which in turn make the tool
self-contained.

View File

@ -1,6 +1,6 @@
# Signature of the current package.
m4_define(AT_PACKAGE_NAME, Kyua - Command line interface)
m4_define(AT_PACKAGE_TARNAME, kyua-cli)
m4_define(AT_PACKAGE_VERSION, 0.6)
m4_define(AT_PACKAGE_STRING, Kyua - Command line interface 0.6)
m4_define(AT_PACKAGE_VERSION, 0.7)
m4_define(AT_PACKAGE_STRING, Kyua - Command line interface 0.7)
m4_define(AT_PACKAGE_BUGREPORT, kyua-discuss@googlegroups.com)

View File

@ -911,7 +911,7 @@ fi
# List of tests.
if $at_list_p; then
cat <<_ATEOF || at_write_fail=1
Kyua - Command line interface 0.6 test suite: bootstrapping tests test groups:
Kyua - Command line interface 0.7 test suite: bootstrapping tests test groups:
NUM: FILE-NAME:LINE TEST-GROUP-NAME
KEYWORDS
@ -952,7 +952,7 @@ _ATEOF
exit $at_write_fail
fi
if $at_version_p; then
$as_echo "$as_me (Kyua - Command line interface 0.6)" &&
$as_echo "$as_me (Kyua - Command line interface 0.7)" &&
cat <<\_ATEOF || at_write_fail=1
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1129,11 +1129,11 @@ exec 5>>"$at_suite_log"
# Banners and logs.
$as_echo "## ------------------------------------------------------------------ ##
## Kyua - Command line interface 0.6 test suite: bootstrapping tests. ##
## Kyua - Command line interface 0.7 test suite: bootstrapping tests. ##
## ------------------------------------------------------------------ ##"
{
$as_echo "## ------------------------------------------------------------------ ##
## Kyua - Command line interface 0.6 test suite: bootstrapping tests. ##
## Kyua - Command line interface 0.7 test suite: bootstrapping tests. ##
## ------------------------------------------------------------------ ##"
echo
@ -1977,7 +1977,7 @@ _ASBOX
$as_echo "Please send $at_msg and all information you think might help:
To: <kyua-discuss@googlegroups.com>
Subject: [Kyua - Command line interface 0.6] $as_me: $at_fail_list${at_fail_list:+ failed${at_xpass_list:+, }}$at_xpass_list${at_xpass_list:+ passed unexpectedly}
Subject: [Kyua - Command line interface 0.7] $as_me: $at_fail_list${at_fail_list:+ failed${at_xpass_list:+, }}$at_xpass_list${at_xpass_list:+ passed unexpectedly}
You may investigate any problem if you feel able to do so, in which
case the test suite provides a good starting point. Its output may

View File

@ -58,45 +58,6 @@ using utils::optional;
namespace {
/// Collection of result types.
///
/// This is a vector rather than a set because we want to respect the order in
/// which the user provided the types.
typedef std::vector< engine::test_result::result_type > result_types;
/// Converts a set of result type names to identifiers.
///
/// \param names The collection of names to process; may be empty.
///
/// \return The result type identifiers corresponding to the input names.
///
/// \throw std::runtime_error If any name in the input names is invalid.
static result_types
parse_types(const std::vector< std::string >& names)
{
using engine::test_result;
typedef std::map< std::string, test_result::result_type > types_map;
types_map valid_types;
valid_types["broken"] = test_result::broken;
valid_types["failed"] = test_result::failed;
valid_types["passed"] = test_result::passed;
valid_types["skipped"] = test_result::skipped;
valid_types["xfail"] = test_result::expected_failure;
result_types types;
for (std::vector< std::string >::const_iterator iter = names.begin();
iter != names.end(); ++iter) {
const types_map::const_iterator match = valid_types.find(*iter);
if (match == valid_types.end())
throw std::runtime_error(F("Unknown result type '%s'") % *iter);
else
types.push_back((*match).second);
}
return types;
}
/// Generates a plain-text report intended to be printed to the console.
class console_hooks : public scan_action::base_hooks {
/// Indirection to print the output to the correct file stream.
@ -106,7 +67,7 @@ class console_hooks : public scan_action::base_hooks {
const bool _show_context;
/// Collection of result types to include in the report.
const result_types& _results_filters;
const cli::result_types& _results_filters;
/// The action ID loaded.
int64_t _action_id;
@ -218,7 +179,7 @@ public:
/// Cannot be empty.
console_hooks(cmdline::ui* ui_, const fs::path& outfile_,
const bool show_context_,
const result_types& results_filters_) :
const cli::result_types& results_filters_) :
_writer(ui_, outfile_),
_show_context(show_context_),
_results_filters(results_filters_)
@ -265,7 +226,7 @@ public:
titles[engine::test_result::passed] = "Passed tests";
titles[engine::test_result::skipped] = "Skipped tests";
for (result_types::const_iterator iter = _results_filters.begin();
for (cli::result_types::const_iterator iter = _results_filters.begin();
iter != _results_filters.end(); ++iter) {
const types_map::const_iterator match = titles.find(*iter);
INV_MSG(match != titles.end(), "Conditional does not match user "
@ -350,9 +311,7 @@ cmd_report::cmd_report(void) : cli_command(
add_option(cmdline::path_option(
"output", "The file to which to write the report",
"path", "/dev/stdout"));
add_option(cmdline::list_option(
"results-filter", "Comma-separated list of result types to include in "
"the report", "types", "skipped,xfail,broken,failed"));
add_option(results_filter_option);
}
@ -372,16 +331,7 @@ cmd_report::run(cmdline::ui* ui, const cmdline::parsed_cmdline& cmdline,
if (cmdline.has_option("action"))
action_id = cmdline.get_option< cmdline::int_option >("action");
result_types types = parse_types(
cmdline.get_option< cmdline::list_option >("results-filter"));
if (types.empty()) {
types.push_back(engine::test_result::passed);
types.push_back(engine::test_result::skipped);
types.push_back(engine::test_result::expected_failure);
types.push_back(engine::test_result::broken);
types.push_back(engine::test_result::failed);
}
const result_types types = get_result_types(cmdline);
console_hooks hooks(
ui, cmdline.get_option< cmdline::path_option >("output"),
cmdline.has_option("show-context"), types);

View File

@ -28,6 +28,7 @@
#include "cli/cmd_report_html.hpp"
#include <algorithm>
#include <cerrno>
#include <cstdlib>
#include <stdexcept>
@ -139,9 +140,15 @@ class html_hooks : public scan_action::base_hooks {
/// The top directory in which to create the HTML files.
fs::path _directory;
/// Collection of result types to include in the report.
const cli::result_types& _results_filters;
/// Templates accumulator to generate the index.html file.
text::templates_def _summary_templates;
/// Mapping of result types to the amount of tests with such result.
std::map< engine::test_result::result_type, std::size_t > _types_count;
/// Generates a common set of templates for all of our files.
///
/// \return A new templates object with common parameters.
@ -157,10 +164,19 @@ class html_hooks : public scan_action::base_hooks {
///
/// \param test_case The test case to be added.
/// \param result The result of the test case.
/// \param has_detail If true, the result of the test case has not been
/// filtered and therefore there exists a separate file for the test
/// with all of its information.
void
add_to_summary(const engine::test_case& test_case,
const engine::test_result& result)
const engine::test_result& result,
const bool has_detail)
{
++_types_count[result.type()];
if (!has_detail)
return;
std::string test_cases_vector;
std::string test_cases_file_vector;
switch (result.type()) {
@ -221,16 +237,40 @@ class html_hooks : public scan_action::base_hooks {
text::instantiate(templates, template_file, output_path);
}
/// Gets the number of tests with a given result type.
///
/// \param type The type to be queried.
///
/// \return The number of tests of the given type, or 0 if none have yet
/// been registered by add_to_summary().
std::size_t
get_count(const engine::test_result::result_type type) const
{
const std::map< engine::test_result::result_type,
std::size_t >::const_iterator
iter = _types_count.find(type);
if (iter == _types_count.end())
return 0;
else
return (*iter).second;
}
public:
/// Constructor for the hooks.
///
/// \param ui_ User interface object where to report progress.
/// \param directory_ The directory in which to create the HTML files.
html_hooks(cmdline::ui* ui_, const fs::path& directory_) :
/// \param results_filters_ The result types to include in the report.
/// Cannot be empty.
html_hooks(cmdline::ui* ui_, const fs::path& directory_,
const cli::result_types& results_filters_) :
_ui(ui_),
_directory(directory_),
_results_filters(results_filters_),
_summary_templates(common_templates())
{
PRE(!results_filters_.empty());
// Keep in sync with add_to_summary().
_summary_templates.add_vector("broken_test_cases");
_summary_templates.add_vector("broken_test_cases_file");
@ -274,7 +314,13 @@ public:
const engine::test_case& test_case = *test_program->find(
iter.test_case_name());
add_to_summary(test_case, result);
if (std::find(_results_filters.begin(), _results_filters.end(),
result.type()) == _results_filters.end()) {
add_to_summary(test_case, result, false);
return;
}
add_to_summary(test_case, result, true);
text::templates_def templates = common_templates();
templates.add_variable("test_case",
@ -308,10 +354,26 @@ public:
void
write_summary(void)
{
const std::size_t bad_count =
_summary_templates.get_vector("broken_test_cases").size() +
_summary_templates.get_vector("failed_test_cases").size();
_summary_templates.add_variable("bad_tests_count", F("%s") % bad_count);
const std::size_t n_passed = get_count(engine::test_result::passed);
const std::size_t n_failed = get_count(engine::test_result::failed);
const std::size_t n_skipped = get_count(engine::test_result::skipped);
const std::size_t n_xfail = get_count(
engine::test_result::expected_failure);
const std::size_t n_broken = get_count(engine::test_result::broken);
const std::size_t n_bad = n_broken + n_failed;
_summary_templates.add_variable("passed_tests_count",
F("%s") % n_passed);
_summary_templates.add_variable("failed_tests_count",
F("%s") % n_failed);
_summary_templates.add_variable("skipped_tests_count",
F("%s") % n_skipped);
_summary_templates.add_variable("xfail_tests_count",
F("%s") % n_xfail);
_summary_templates.add_variable("broken_tests_count",
F("%s") % n_broken);
_summary_templates.add_variable("bad_tests_count", F("%s") % n_bad);
generate(text::templates_def(), "report.css", "report.css");
generate(_summary_templates, "index.html", "index.html");
@ -337,6 +399,9 @@ cli::cmd_report_html::cmd_report_html(void) : cli_command(
add_option(cmdline::path_option(
"output", "The directory in which to store the HTML files",
"path", "html"));
add_option(cmdline::list_option(
"results-filter", "Comma-separated list of result types to include in "
"the report", "types", "skipped,xfail,broken,failed"));
}
@ -357,10 +422,11 @@ cli::cmd_report_html::run(cmdline::ui* ui,
if (cmdline.has_option("action"))
action_id = cmdline.get_option< cmdline::int_option >("action");
const result_types types = get_result_types(cmdline);
const fs::path directory =
cmdline.get_option< cmdline::path_option >("output");
create_top_directory(directory, cmdline.has_option("force"));
html_hooks hooks(ui, directory);
html_hooks hooks(ui, directory, types);
scan_action::drive(store_path(cmdline), action_id, hooks);
hooks.write_summary();

View File

@ -68,6 +68,12 @@ const cmdline::path_option cli::kyuafile_option(
"file", "Kyuafile");
/// Standard definition of the option to specify filters on test results.
const cmdline::list_option cli::results_filter_option(
"results-filter", "Comma-separated list of result types to include in "
"the report", "types", "skipped,xfail,broken,failed");
/// Standard definition of the option to specify the store.
const cmdline::path_option cli::store_option(
's', "store",
@ -75,6 +81,44 @@ const cmdline::path_option cli::store_option(
"file", "~/.kyua/store.db");
namespace {
/// Converts a set of result type names to identifiers.
///
/// \param names The collection of names to process; may be empty.
///
/// \return The result type identifiers corresponding to the input names.
///
/// \throw std::runtime_error If any name in the input names is invalid.
static cli::result_types
parse_types(const std::vector< std::string >& names)
{
using engine::test_result;
typedef std::map< std::string, test_result::result_type > types_map;
types_map valid_types;
valid_types["broken"] = test_result::broken;
valid_types["failed"] = test_result::failed;
valid_types["passed"] = test_result::passed;
valid_types["skipped"] = test_result::skipped;
valid_types["xfail"] = test_result::expected_failure;
cli::result_types types;
for (std::vector< std::string >::const_iterator iter = names.begin();
iter != names.end(); ++iter) {
const types_map::const_iterator match = valid_types.find(*iter);
if (match == valid_types.end())
throw std::runtime_error(F("Unknown result type '%s'") % *iter);
else
types.push_back((*match).second);
}
return types;
}
} // anonymous namespace
/// Gets the path to the build root, if any.
///
/// This is just syntactic sugar to simplify quierying the 'build_root_option'.
@ -129,6 +173,29 @@ cli::kyuafile_path(const cmdline::parsed_cmdline& cmdline)
}
/// Gets the filters for the result types.
///
/// \param cmdline The parsed command line.
///
/// \return A collection of result types to be used for filtering.
///
/// \throw std::runtime_error If any of the user-provided filters is invalid.
cli::result_types
cli::get_result_types(const utils::cmdline::parsed_cmdline& cmdline)
{
result_types types = parse_types(
cmdline.get_option< cmdline::list_option >("results-filter"));
if (types.empty()) {
types.push_back(engine::test_result::passed);
types.push_back(engine::test_result::skipped);
types.push_back(engine::test_result::expected_failure);
types.push_back(engine::test_result::broken);
types.push_back(engine::test_result::failed);
}
return types;
}
/// Gets the path to the store to be used.
///
/// This has the side-effect of creating the directory in which to store the

View File

@ -34,7 +34,9 @@
#include <memory>
#include <set>
#include <vector>
#include "engine/test_result.hpp"
#include "utils/cmdline/base_command.hpp"
#include "utils/cmdline/options.hpp"
#include "utils/cmdline/parser.hpp"
@ -51,9 +53,8 @@ class path;
} // namespace utils
namespace engine {
struct test_filter;
class test_case;
class test_result;
class test_filter;
} // namespace engine
namespace cli {
@ -61,6 +62,7 @@ namespace cli {
extern const utils::cmdline::path_option build_root_option;
extern const utils::cmdline::path_option kyuafile_option;
extern const utils::cmdline::list_option results_filter_option;
extern const utils::cmdline::path_option store_option;
extern const utils::cmdline::property_option variable_option;
@ -77,11 +79,19 @@ typedef utils::cmdline::base_command< utils::config::tree > cli_command;
typedef std::auto_ptr< cli_command > cli_command_ptr;
/// Collection of result types.
///
/// This is a vector rather than a set because we want to respect the order in
/// which the user provided the types.
typedef std::vector< engine::test_result::result_type > result_types;
utils::optional< utils::fs::path > get_home(void);
utils::optional< utils::fs::path > build_root_path(
const utils::cmdline::parsed_cmdline&);
utils::fs::path kyuafile_path(const utils::cmdline::parsed_cmdline&);
result_types get_result_types(const utils::cmdline::parsed_cmdline&);
utils::fs::path store_path(const utils::cmdline::parsed_cmdline&);
std::set< engine::test_filter > parse_filters(

View File

@ -143,6 +143,83 @@ ATF_TEST_CASE_BODY(kyuafile_path__explicit)
}
ATF_TEST_CASE_WITHOUT_HEAD(result_types__default);
ATF_TEST_CASE_BODY(result_types__default)
{
std::map< std::string, std::vector< std::string > > options;
options["results-filter"].push_back(
cli::results_filter_option.default_value());
const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
cli::result_types exp_types;
exp_types.push_back(engine::test_result::skipped);
exp_types.push_back(engine::test_result::expected_failure);
exp_types.push_back(engine::test_result::broken);
exp_types.push_back(engine::test_result::failed);
ATF_REQUIRE(exp_types == cli::get_result_types(mock_cmdline));
}
ATF_TEST_CASE_WITHOUT_HEAD(result_types__empty);
ATF_TEST_CASE_BODY(result_types__empty)
{
std::map< std::string, std::vector< std::string > > options;
options["results-filter"].push_back("");
const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
cli::result_types exp_types;
exp_types.push_back(engine::test_result::passed);
exp_types.push_back(engine::test_result::skipped);
exp_types.push_back(engine::test_result::expected_failure);
exp_types.push_back(engine::test_result::broken);
exp_types.push_back(engine::test_result::failed);
ATF_REQUIRE(exp_types == cli::get_result_types(mock_cmdline));
}
ATF_TEST_CASE_WITHOUT_HEAD(result_types__explicit__all);
ATF_TEST_CASE_BODY(result_types__explicit__all)
{
std::map< std::string, std::vector< std::string > > options;
options["results-filter"].push_back("passed,skipped,xfail,broken,failed");
const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
cli::result_types exp_types;
exp_types.push_back(engine::test_result::passed);
exp_types.push_back(engine::test_result::skipped);
exp_types.push_back(engine::test_result::expected_failure);
exp_types.push_back(engine::test_result::broken);
exp_types.push_back(engine::test_result::failed);
ATF_REQUIRE(exp_types == cli::get_result_types(mock_cmdline));
}
ATF_TEST_CASE_WITHOUT_HEAD(result_types__explicit__some);
ATF_TEST_CASE_BODY(result_types__explicit__some)
{
std::map< std::string, std::vector< std::string > > options;
options["results-filter"].push_back("skipped,broken");
const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
cli::result_types exp_types;
exp_types.push_back(engine::test_result::skipped);
exp_types.push_back(engine::test_result::broken);
ATF_REQUIRE(exp_types == cli::get_result_types(mock_cmdline));
}
ATF_TEST_CASE_WITHOUT_HEAD(result_types__explicit__invalid);
ATF_TEST_CASE_BODY(result_types__explicit__invalid)
{
std::map< std::string, std::vector< std::string > > options;
options["results-filter"].push_back("skipped,foo,broken");
const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
ATF_REQUIRE_THROW_RE(std::runtime_error, "Unknown result type 'foo'",
cli::get_result_types(mock_cmdline));
}
ATF_TEST_CASE_WITHOUT_HEAD(store_path__default__create_directory__ok);
ATF_TEST_CASE_BODY(store_path__default__create_directory__ok)
{
@ -355,6 +432,12 @@ ATF_INIT_TEST_CASES(tcs)
ATF_ADD_TEST_CASE(tcs, kyuafile_path__default);
ATF_ADD_TEST_CASE(tcs, kyuafile_path__explicit);
ATF_ADD_TEST_CASE(tcs, result_types__default);
ATF_ADD_TEST_CASE(tcs, result_types__empty);
ATF_ADD_TEST_CASE(tcs, result_types__explicit__all);
ATF_ADD_TEST_CASE(tcs, result_types__explicit__some);
ATF_ADD_TEST_CASE(tcs, result_types__explicit__invalid);
ATF_ADD_TEST_CASE(tcs, store_path__default__create_directory__ok);
ATF_ADD_TEST_CASE(tcs, store_path__default__create_directory__fail);
ATF_ADD_TEST_CASE(tcs, store_path__default__no_home);

View File

@ -25,7 +25,7 @@
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.Dd September 9, 2012
.Dd April 15, 2013
.Dt KYUA-REPORT-HTML 1
.Os
.Sh NAME
@ -36,6 +36,7 @@
.Op Fl -action Ar id
.Op Fl -force
.Op Fl -output Ar path
.Op Fl -results-filter Ar types
.Op Fl -store Ar file
.Sh DESCRIPTION
The
@ -64,6 +65,24 @@ directory must not exist unless the
.Fl -force
option is provided. The default is
.Pa ./html .
.It Fl -results-filter Ar types
Comma-separated list of the test result types to include in the report.
The ordering of the values is respected so that you can determine how you
want the list of tests to be shown.
.Pp
The valid values are:
.Sq broken ,
.Sq failed ,
.Sq passed ,
.Sq skipped
and
.Sq xfail .
If the parameter supplied to the option is empty, filtering is suppressed
and all result types are shown in the report.
.Pp
The default value for this flag includes all the test results except the
passed tests. Showing the passed tests by default clutters the report with
too much information, so only abnormal conditions are included.
.It Fl -store Ar path , Fl s Ar path
Specifies the database to use. Defaults to
.Pa ~/.kyua/store.db .

View File

@ -33,7 +33,8 @@
#define ENGINE_ACTION_HPP
#include <ostream>
#include <tr1/memory>
#include "utils/shared_ptr.hpp"
namespace engine {
@ -50,7 +51,7 @@ class action {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
public:
explicit action(const context&);

View File

@ -35,9 +35,9 @@
#include <map>
#include <ostream>
#include <string>
#include <tr1/memory>
#include "utils/fs/path.hpp"
#include "utils/shared_ptr.hpp"
namespace engine {
@ -51,7 +51,7 @@ class context {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
public:
context(const utils::fs::path&,

View File

@ -49,7 +49,8 @@ namespace debug_test {
/// Tuple containing the results of this driver.
struct result {
class result {
public:
/// A filter matching the executed test case only.
test_filter test_case;

View File

@ -61,7 +61,8 @@ public:
/// Tuple containing the results of this driver.
struct result {
class result {
public:
/// Filters that did not match any available test case.
///
/// The presence of any filters here probably indicates a usage error. If a

View File

@ -77,7 +77,8 @@ public:
/// Tuple containing the results of this driver.
struct result {
class result {
public:
/// The identifier assigned to the operation.
int64_t action_id;

View File

@ -78,7 +78,8 @@ public:
/// Tuple containing the results of this driver.
struct result {
class result {
public:
/// Initializer for the tuple's fields.
result(void)
{

View File

@ -52,7 +52,8 @@ namespace engine {
/// A filter is one of: the name of a directory containing test cases, the name
/// of a test program, or the name of a test program plus the name of a test
/// case.
struct test_filter {
class test_filter {
public:
/// The name of the test program or subdirectory to match.
utils::fs::path test_program;

View File

@ -38,9 +38,8 @@
#include <set>
#include <string>
#include <tr1/memory>
#include "utils/noncopyable.hpp"
#include "utils/shared_ptr.hpp"
namespace utils {
namespace config { class tree; }
@ -73,7 +72,7 @@ class metadata {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
friend class metadata_builder;

View File

@ -338,7 +338,7 @@ ATF_TEST_CASE_BODY(output__some_values)
ATF_REQUIRE_EQ(
"metadata{allowed_architectures='abc', allowed_platforms='', "
"description='', has_cleanup='false', required_configs='', "
"required_files='bar foo', required_memory='1024', "
"required_files='bar foo', required_memory='1.00K', "
"required_programs='', required_user='', timeout='300'}",
str.str());
}

View File

@ -418,18 +418,32 @@ engine::debug_test_case(const test_case* test_case,
const engine::test_program& test_program =
test_case->container_test_program();
const engine::tester tester = create_tester(
test_program.interface_name(), test_case->get_metadata(), user_config);
tester.test(test_program.absolute_path(), test_case->name(),
result_file.file(), stdout_path, stderr_path,
generate_tester_config(test_case->get_metadata(), user_config,
test_program.test_suite_name()));
try {
const engine::tester tester = create_tester(
test_program.interface_name(), test_case->get_metadata(),
user_config);
tester.test(test_program.absolute_path(), test_case->name(),
result_file.file(), stdout_path, stderr_path,
generate_tester_config(test_case->get_metadata(),
user_config,
test_program.test_suite_name()));
hooks.got_stdout(stdout_path);
hooks.got_stderr(stderr_path);
hooks.got_stdout(stdout_path);
hooks.got_stderr(stderr_path);
std::ifstream result_input(result_file.file().c_str());
return engine::test_result::parse(result_input);
std::ifstream result_input(result_file.file().c_str());
return engine::test_result::parse(result_input);
} catch (const std::runtime_error& e) {
// One of the possible explanation for us getting here is if the tester
// crashes or doesn't behave as expected. We must record any output
// from the process so that we can debug it further.
hooks.got_stdout(stdout_path);
hooks.got_stderr(stderr_path);
return engine::test_result(
engine::test_result::broken,
F("Caught unexpected exception: %s") % e.what());
}
}
@ -467,16 +481,30 @@ engine::run_test_case(const test_case* test_case,
const engine::test_program& test_program =
test_case->container_test_program();
const engine::tester tester = create_tester(
test_program.interface_name(), test_case->get_metadata(), user_config);
tester.test(test_program.absolute_path(), test_case->name(),
result_file.file(), stdout_file.file(), stderr_file.file(),
generate_tester_config(test_case->get_metadata(), user_config,
test_program.test_suite_name()));
try {
const engine::tester tester = create_tester(
test_program.interface_name(), test_case->get_metadata(),
user_config);
tester.test(test_program.absolute_path(), test_case->name(),
result_file.file(), stdout_file.file(), stderr_file.file(),
generate_tester_config(test_case->get_metadata(),
user_config,
test_program.test_suite_name()));
hooks.got_stdout(stdout_file.file());
hooks.got_stderr(stderr_file.file());
hooks.got_stdout(stdout_file.file());
hooks.got_stderr(stderr_file.file());
std::ifstream result_input(result_file.file().c_str());
return engine::test_result::parse(result_input);
std::ifstream result_input(result_file.file().c_str());
return engine::test_result::parse(result_input);
} catch (const std::runtime_error& e) {
// One of the possible explanation for us getting here is if the tester
// crashes or doesn't behave as expected. We must record any output
// from the process so that we can debug it further.
hooks.got_stdout(stdout_file.file());
hooks.got_stderr(stderr_file.file());
return engine::test_result(
engine::test_result::broken,
F("Caught unexpected exception: %s") % e.what());
}
}

View File

@ -34,12 +34,12 @@
#include <ostream>
#include <string>
#include <tr1/memory>
#include "engine/metadata.hpp"
#include "utils/config/tree.hpp"
#include "utils/fs/path.hpp"
#include "utils/optional.hpp"
#include "utils/shared_ptr.hpp"
namespace engine {
@ -71,7 +71,7 @@ class test_case {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
public:
test_case(const std::string&, const test_program&,
@ -96,7 +96,7 @@ std::ostream& operator<<(std::ostream&, const test_case&);
/// Pointer to a test case.
typedef std::tr1::shared_ptr< test_case > test_case_ptr;
typedef std::shared_ptr< test_case > test_case_ptr;
test_result debug_test_case(const test_case*, const utils::config::tree&,

View File

@ -364,6 +364,30 @@ public:
};
/// Creates a mock tester that receives a signal.
///
/// \param interface The name of the interface implemented by the tester.
/// \param term_sig Signal to deliver to the tester. If the tester does not
/// exit due to this reason, it exits with an arbitrary non-zero code.
static void
create_mock_tester_signal(const char* interface, const int term_sig)
{
const std::string tester_name = F("kyua-%s-tester") % interface;
atf::utils::create_file(
tester_name,
F("#! /bin/sh\n"
"echo 'stdout stuff'\n"
"echo 'stderr stuff' 1>&2\n"
"kill -%s $$\n"
"echo 'not reachable' 1>&2\n"
"exit 0\n") % term_sig);
ATF_REQUIRE(::chmod(tester_name.c_str(), 0755) != -1);
utils::setenv("KYUA_TESTERSDIR", fs::current_path().str());
}
} // anonymous namespace
@ -513,6 +537,23 @@ ATF_TEST_CASE_BODY(test_case__operators_eq_and_ne__not_copy)
}
ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__tester_crashes);
ATF_TEST_CASE_BODY(run_test_case__tester_crashes)
{
atf_helper helper(this, "pass");
helper.move("program", ".");
create_mock_tester_signal("atf", SIGSEGV);
capture_hooks hooks;
const engine::test_result result = helper.run(hooks);
ATF_REQUIRE(engine::test_result::broken == result.type());
ATF_REQUIRE_MATCH("Tester received signal.*bug", result.reason());
ATF_REQUIRE_EQ("stdout stuff\n", hooks.stdout_contents);
ATF_REQUIRE_EQ("stderr stuff\n", hooks.stderr_contents);
}
ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__current_directory);
ATF_TEST_CASE_BODY(run_test_case__atf__current_directory)
{
@ -1064,6 +1105,8 @@ ATF_INIT_TEST_CASES(tcs)
ATF_ADD_TEST_CASE(tcs, test_case__output);
ATF_ADD_TEST_CASE(tcs, run_test_case__tester_crashes);
ATF_ADD_TEST_CASE(tcs, run_test_case__atf__current_directory);
ATF_ADD_TEST_CASE(tcs, run_test_case__atf__subdirectory);
ATF_ADD_TEST_CASE(tcs, run_test_case__atf__config_variables);

View File

@ -40,11 +40,11 @@
#include <ostream>
#include <string>
#include <tr1/memory>
#include <vector>
#include "engine/test_case.hpp"
#include "utils/fs/path.hpp"
#include "utils/shared_ptr.hpp"
namespace engine {
@ -61,7 +61,7 @@ class test_program {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
public:
test_program(const std::string&, const utils::fs::path&,
@ -89,7 +89,7 @@ std::ostream& operator<<(std::ostream&, const test_program&);
/// Pointer to a test program.
typedef std::tr1::shared_ptr< test_program > test_program_ptr;
typedef std::shared_ptr< test_program > test_program_ptr;
/// Collection of test programs.

View File

@ -28,17 +28,53 @@
#include "engine/test_program.hpp"
extern "C" {
#include <sys/stat.h>
#include <signal.h>
}
#include <sstream>
#include <atf-c++.hpp>
#include "engine/exceptions.hpp"
#include "engine/test_result.hpp"
#include "utils/env.hpp"
#include "utils/format/macros.hpp"
#include "utils/fs/operations.hpp"
#include "utils/fs/path.hpp"
#include "utils/optional.ipp"
namespace fs = utils::fs;
namespace {
/// Creates a mock tester that receives a signal.
///
/// \param term_sig Signal to deliver to the tester. If the tester does not
/// exit due to this reason, it exits with an arbitrary non-zero code.
static void
create_mock_tester_signal(const int term_sig)
{
const std::string tester_name = "kyua-mock-tester";
atf::utils::create_file(
tester_name,
F("#! /bin/sh\n"
"kill -%s $$\n"
"exit 0\n") % term_sig);
ATF_REQUIRE(::chmod(tester_name.c_str(), 0755) != -1);
utils::setenv("KYUA_TESTERSDIR", fs::current_path().str());
}
} // anonymous namespace
ATF_TEST_CASE_WITHOUT_HEAD(ctor_and_getters);
ATF_TEST_CASE_BODY(ctor_and_getters)
{
@ -114,6 +150,27 @@ ATF_TEST_CASE_BODY(test_cases__some)
}
ATF_TEST_CASE_WITHOUT_HEAD(test_cases__tester_fails);
ATF_TEST_CASE_BODY(test_cases__tester_fails)
{
engine::test_program test_program(
"mock", fs::path("non-existent"), fs::path("."), "suite-name",
engine::metadata_builder().build());
create_mock_tester_signal(SIGSEGV);
const engine::test_cases_vector& test_cases = test_program.test_cases();
ATF_REQUIRE_EQ(1, test_cases.size());
const engine::test_case_ptr& test_case = test_cases[0];
ATF_REQUIRE_EQ("__test_cases_list__", test_case->name());
ATF_REQUIRE(test_case->fake_result());
const engine::test_result result = test_case->fake_result().get();
ATF_REQUIRE(engine::test_result::broken == result.type());
ATF_REQUIRE_MATCH("Tester did not exit cleanly", result.reason());
}
ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__copy);
ATF_TEST_CASE_BODY(operators_eq_and_ne__copy)
{
@ -318,6 +375,7 @@ ATF_INIT_TEST_CASES(tcs)
ATF_ADD_TEST_CASE(tcs, find__missing);
ATF_ADD_TEST_CASE(tcs, test_cases__get);
ATF_ADD_TEST_CASE(tcs, test_cases__some);
ATF_ADD_TEST_CASE(tcs, test_cases__tester_fails);
ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__copy);
ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__not_copy);

View File

@ -304,6 +304,7 @@ engine::tester::test(const fs::path& program, const std::string& test_case_name,
}
} else {
INV(status.signaled());
throw engine::error("Tester received a signal; this is a bug");
throw engine::error(F("Tester received signal %s; this is a bug") %
status.termsig());
}
}

View File

@ -30,6 +30,8 @@
extern "C" {
#include <sys/stat.h>
#include <signal.h>
}
#include <cstdlib>
@ -56,7 +58,7 @@ using utils::optional;
namespace {
/// Creates a mock tester.
/// Creates a mock tester that exits cleanly.
///
/// The interface accepted by the tester is 'mock'. This tester outputs the
/// arguments passed to it and then prints a message to both the stdout and the
@ -64,7 +66,7 @@ namespace {
///
/// \param exit_status Code to exit with.
static void
create_mock_tester(const int exit_status)
create_mock_tester_exit(const int exit_status)
{
atf::utils::create_file(
"kyua-mock-tester",
@ -82,13 +84,42 @@ create_mock_tester(const int exit_status)
}
/// Creates a mock tester that receives a signal.
///
/// The interface accepted by the tester is 'mock'. This tester outputs the
/// arguments passed to it and then prints a message to both the stdout and the
/// stderr.
///
/// \param term_sig Signal to deliver to the tester. If the tester does not
/// exit due to this reason, it exits with an arbitrary non-zero code.
static void
create_mock_tester_signal(const int term_sig)
{
atf::utils::create_file(
"kyua-mock-tester",
F("#! /bin/sh\n"
"while [ ${#} -gt 0 ]; do\n"
" echo \"Arg: ${1}\"\n"
" shift\n"
"done\n"
"echo 'tester output'\n"
"echo 'tester error' 1>&2\n"
"kill -%s $$\n"
"echo 'signal did not terminate the process\n"
"exit 0\n") % term_sig);
ATF_REQUIRE(::chmod("kyua-mock-tester", 0755) != -1);
utils::setenv("KYUA_TESTERSDIR", fs::current_path().str());
}
} // anonymous namespace
ATF_TEST_CASE_WITHOUT_HEAD(tester__list__defaults);
ATF_TEST_CASE_BODY(tester__list__defaults)
{
create_mock_tester(EXIT_SUCCESS);
create_mock_tester_exit(EXIT_SUCCESS);
engine::tester tester("mock", none, none);
const std::string output = tester.list(fs::path("/foo/bar"));
@ -107,7 +138,7 @@ ATF_TEST_CASE_BODY(tester__list__explicit_common_args)
const passwd::user user("fake", 123, 456);
const datetime::delta timeout(15, 0);
create_mock_tester(EXIT_SUCCESS);
create_mock_tester_exit(EXIT_SUCCESS);
engine::tester tester("mock", utils::make_optional(user),
utils::make_optional(timeout));
const std::string output = tester.list(fs::path("/another/program/1"));
@ -137,7 +168,19 @@ ATF_TEST_CASE_BODY(tester__list__unknown_interface)
ATF_TEST_CASE_WITHOUT_HEAD(tester__list__tester_fails);
ATF_TEST_CASE_BODY(tester__list__tester_fails)
{
create_mock_tester(EXIT_FAILURE);
create_mock_tester_exit(EXIT_FAILURE);
engine::tester tester("mock", none, none);
ATF_REQUIRE_THROW_RE(
engine::error,
"Tester did not exit cleanly:.*tester output.*tester error",
tester.list(fs::path("does-not-matter")));
}
ATF_TEST_CASE_WITHOUT_HEAD(tester__list__tester_crashes);
ATF_TEST_CASE_BODY(tester__list__tester_crashes)
{
create_mock_tester_signal(SIGKILL);
engine::tester tester("mock", none, none);
ATF_REQUIRE_THROW_RE(
engine::error,
@ -151,7 +194,7 @@ ATF_TEST_CASE_BODY(tester__test__defaults)
{
std::map< std::string, std::string > vars;
create_mock_tester(EXIT_FAILURE);
create_mock_tester_exit(EXIT_FAILURE);
engine::tester tester("mock", none, none);
tester.test(fs::path("/foo/bar"), "test-case", fs::path("/the/result/file"),
fs::path("tester.out"), fs::path("tester.err"), vars);
@ -179,7 +222,7 @@ ATF_TEST_CASE_BODY(tester__test__explicit_common_args_and_vars)
vars["var1"] = "value1";
vars["variable-2"] = "value with spaces";
create_mock_tester(EXIT_SUCCESS);
create_mock_tester_exit(EXIT_SUCCESS);
engine::tester tester("mock", utils::make_optional(user),
utils::make_optional(timeout));
tester.test(fs::path("/foo/bar"), "test-case", fs::path("/the/result/file"),
@ -221,7 +264,7 @@ ATF_TEST_CASE_BODY(tester__test__tester_fails)
{
const std::map< std::string, std::string > vars;
create_mock_tester(2);
create_mock_tester_exit(2);
engine::tester tester("mock", none, none);
ATF_REQUIRE_THROW_RE(
engine::error,
@ -231,6 +274,21 @@ ATF_TEST_CASE_BODY(tester__test__tester_fails)
}
ATF_TEST_CASE_WITHOUT_HEAD(tester__test__tester_crashes);
ATF_TEST_CASE_BODY(tester__test__tester_crashes)
{
const std::map< std::string, std::string > vars;
create_mock_tester_signal(SIGKILL);
engine::tester tester("mock", none, none);
ATF_REQUIRE_THROW_RE(
engine::error,
F("Tester received signal %s; this is a bug") % SIGKILL,
tester.test(fs::path("foo"), "bar", fs::path("baz"),
fs::path("out"), fs::path("err"), vars));
}
ATF_TEST_CASE_WITHOUT_HEAD(tester_path__default);
ATF_TEST_CASE_BODY(tester_path__default)
{
@ -302,11 +360,13 @@ ATF_INIT_TEST_CASES(tcs)
ATF_ADD_TEST_CASE(tcs, tester__list__explicit_common_args);
ATF_ADD_TEST_CASE(tcs, tester__list__unknown_interface);
ATF_ADD_TEST_CASE(tcs, tester__list__tester_fails);
ATF_ADD_TEST_CASE(tcs, tester__list__tester_crashes);
ATF_ADD_TEST_CASE(tcs, tester__test__defaults);
ATF_ADD_TEST_CASE(tcs, tester__test__explicit_common_args_and_vars);
ATF_ADD_TEST_CASE(tcs, tester__test__unknown_interface);
ATF_ADD_TEST_CASE(tcs, tester__test__tester_fails);
ATF_ADD_TEST_CASE(tcs, tester__test__tester_crashes);
ATF_ADD_TEST_CASE(tcs, tester_path__default);
ATF_ADD_TEST_CASE(tcs, tester_path__custom);

View File

@ -348,11 +348,8 @@ bogus_kyuafile_body() {
cat >Kyuafile <<EOF
Hello, world.
EOF
cat >experr <<EOF
kyua: E: Load of 'Kyuafile' failed: Failed to load Lua file 'Kyuafile': Kyuafile:2: '<name>' expected near '<eof>'.
EOF
atf_check -s exit:2 -o empty -e file:experr kyua debug foo:bar
atf_check -s exit:2 -o empty \
-e match:"Load of 'Kyuafile' failed: .* Kyuafile:2:" kyua list
}

View File

@ -486,11 +486,8 @@ bogus_kyuafile_body() {
cat >Kyuafile <<EOF
Hello, world.
EOF
cat >experr <<EOF
kyua: E: Load of 'Kyuafile' failed: Failed to load Lua file 'Kyuafile': Kyuafile:2: '<name>' expected near '<eof>'.
EOF
atf_check -s exit:2 -o empty -e file:experr kyua list
atf_check -s exit:2 -o empty \
-e match:"Load of 'Kyuafile' failed: .* Kyuafile:2:" kyua list
}

View File

@ -80,7 +80,7 @@ check_in_file() {
if grep "${1}" "${file}" >/dev/null; then
:
else
atf_fail "Test case output not found in HTML page"
atf_fail "Test case output not found in HTML page ${file}"
fi
shift
done
@ -114,27 +114,14 @@ default_behavior__ok_body() {
for f in \
html/index.html \
html/context.html \
html/simple_all_pass_pass.html \
html/simple_all_pass_skip.html \
html/simple_some_fail_fail.html \
html/simple_some_fail_pass.html \
html/metadata_no_properties.html \
html/metadata_one_property.html \
html/metadata_many_properties.html \
html/metadata_with_cleanup.html
html/simple_some_fail_fail.html
do
test -f "${f}" || atf_fail "Missing ${f}"
done
atf_check -o match:"2 TESTS FAILING" cat html/index.html
check_in_file html/simple_all_pass_pass.html \
"This is the stdout of pass" "This is the stderr of pass"
check_not_in_file html/simple_all_pass_pass.html \
"This is the stdout of skip" "This is the stderr of skip" \
"This is the stdout of fail" "This is the stderr of fail" \
"Test case did not write anything to"
check_in_file html/simple_all_pass_skip.html \
"This is the stdout of skip" "This is the stderr of skip"
check_not_in_file html/simple_all_pass_skip.html \
@ -149,14 +136,6 @@ default_behavior__ok_body() {
"This is the stdout of skip" "This is the stderr of skip" \
"Test case did not write anything to"
check_in_file html/simple_some_fail_pass.html \
"Test case did not write anything to stdout" \
"Test case did not write anything to stderr"
check_not_in_file html/simple_some_fail_pass.html \
"This is the stdout of pass" "This is the stderr of pass" \
"This is the stdout of skip" "This is the stderr of skip" \
"This is the stdout of fail" "This is the stderr of fail"
check_in_file html/metadata_one_property.html \
"description = Does nothing but has one metadata property"
check_not_in_file html/metadata_one_property.html \
@ -251,6 +230,54 @@ output__explicit_body() {
}
utils_test_case results_filter__ok
results_filter__ok_body() {
utils_install_timestamp_wrapper
run_tests "mock1"
atf_check -s exit:0 -o ignore -e empty kyua report-html \
--results-filter=passed
for f in \
html/index.html \
html/context.html \
html/simple_all_pass_pass.html \
html/simple_some_fail_pass.html \
html/metadata_no_properties.html \
html/metadata_with_cleanup.html
do
test -f "${f}" || atf_fail "Missing ${f}"
done
atf_check -o match:"2 TESTS FAILING" cat html/index.html
check_in_file html/simple_all_pass_pass.html \
"This is the stdout of pass" "This is the stderr of pass"
check_not_in_file html/simple_all_pass_pass.html \
"This is the stdout of skip" "This is the stderr of skip" \
"This is the stdout of fail" "This is the stderr of fail" \
"Test case did not write anything to"
check_in_file html/simple_some_fail_pass.html \
"Test case did not write anything to stdout" \
"Test case did not write anything to stderr"
check_not_in_file html/simple_some_fail_pass.html \
"This is the stdout of pass" "This is the stderr of pass" \
"This is the stdout of skip" "This is the stderr of skip" \
"This is the stdout of fail" "This is the stderr of fail"
}
utils_test_case results_filter__invalid
results_filter__invalid_body() {
kyua db-exec "SELECT * FROM actions"
echo "kyua: E: Unknown result type 'foo-bar'." >experr
atf_check -s exit:2 -o empty -e file:experr kyua report-html \
--results-filter=passed,foo-bar
}
atf_init_test_cases() {
atf_add_test_case default_behavior__ok
atf_add_test_case default_behavior__no_actions
@ -263,4 +290,7 @@ atf_init_test_cases() {
atf_add_test_case force__no
atf_add_test_case output__explicit
atf_add_test_case results_filter__ok
atf_add_test_case results_filter__invalid
}

View File

@ -889,11 +889,8 @@ bogus_kyuafile_body() {
cat >Kyuafile <<EOF
Hello, world.
EOF
cat >experr <<EOF
kyua: E: Load of 'Kyuafile' failed: Failed to load Lua file 'Kyuafile': Kyuafile:2: '<name>' expected near '<eof>'.
EOF
atf_check -s exit:2 -o empty -e file:experr kyua test
atf_check -s exit:2 -o empty \
-e match:"Load of 'Kyuafile' failed: .* Kyuafile:2:" kyua list
}

View File

@ -66,7 +66,7 @@
%else
<tr>
<td>Broken</td>
<td class="numeric">%%length(broken_test_cases)%%</td>
<td class="numeric">%%broken_tests_count%%</td>
</tr>
%endif
%if length(failed_test_cases)
@ -77,7 +77,7 @@
%else
<tr>
<td>Failed</td>
<td class="numeric">%%length(failed_test_cases)%%</td>
<td class="numeric">%%failed_tests_count%%</td>
</tr>
%endif
<tr>
@ -86,7 +86,7 @@
%else
<td>Expected failures</td>
%endif
<td class="numeric">%%length(xfail_test_cases)%%</td>
<td class="numeric">%%xfail_tests_count%%</td>
</tr>
<tr>
%if length(skipped_test_cases)
@ -94,7 +94,7 @@
%else
<td>Skipped</td>
%endif
<td class="numeric">%%length(skipped_test_cases)%%</td>
<td class="numeric">%%skipped_tests_count%%</td>
</tr>
<tr>
%if length(passed_test_cases)
@ -102,7 +102,7 @@
%else
<td>Passed</td>
%endif
<td class="numeric">%%length(passed_test_cases)%%</td>
<td class="numeric">%%passed_tests_count%%</td>
</tr>
</tbody>
</table>

View File

@ -32,7 +32,7 @@
#if !defined(STORE_BACKEND_HPP)
#define STORE_BACKEND_HPP
#include <tr1/memory>
#include "utils/shared_ptr.hpp"
namespace utils {
namespace fs {
@ -72,7 +72,7 @@ class backend {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
friend class metadata;

View File

@ -437,7 +437,7 @@ struct store::results_iterator::impl {
///
/// \param pimpl_ The internal implementation details of the iterator.
store::results_iterator::results_iterator(
std::tr1::shared_ptr< impl > pimpl_) :
std::shared_ptr< impl > pimpl_) :
_pimpl(pimpl_)
{
}
@ -680,7 +680,7 @@ store::results_iterator
store::transaction::get_action_results(const int64_t action_id)
{
try {
return results_iterator(std::tr1::shared_ptr< results_iterator::impl >(
return results_iterator(std::shared_ptr< results_iterator::impl >(
new results_iterator::impl(_pimpl->_backend, action_id)));
} catch (const sqlite::error& e) {
throw error(e.what());

View File

@ -37,13 +37,13 @@ extern "C" {
}
#include <string>
#include <tr1/memory>
#include <utility>
#include "engine/test_program.hpp"
#include "utils/datetime.hpp"
#include "utils/fs/path.hpp"
#include "utils/optional.hpp"
#include "utils/shared_ptr.hpp"
namespace engine {
class action;
@ -77,10 +77,10 @@ class results_iterator {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
friend class transaction;
results_iterator(std::tr1::shared_ptr< impl >);
results_iterator(std::shared_ptr< impl >);
public:
~results_iterator(void);
@ -106,7 +106,7 @@ class transaction {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
friend class backend;
transaction(backend&);

View File

@ -33,6 +33,7 @@
#define UTILS_CMDLINE_EXCEPTIONS_HPP
#include <stdexcept>
#include <string>
namespace utils {
namespace cmdline {

View File

@ -42,7 +42,7 @@ namespace {
/// Gets the tree singleton stored in the Lua state.
///
/// \param state The Lua state. The metadata of _G must contain a key named
/// \param state The Lua state. The registry must contain a key named
/// "tree" with a pointer to the singleton.
///
/// \return A reference to the tree associated with the Lua state.
@ -53,10 +53,15 @@ get_global_tree(lutok::state& state)
{
lutok::stack_cleaner cleaner(state);
if (!state.get_metafield(lutok::globals_index, "tree"))
state.push_value(lutok::registry_index);
state.push_string("tree");
state.get_table(-2);
if (state.is_nil())
throw config::syntax_error("Cannot find tree singleton; global state "
"corrupted?");
return **state.to_userdata< config::tree* >();
config::tree& tree = **state.to_userdata< config::tree* >();
state.pop(1);
return tree;
}
@ -254,7 +259,7 @@ config::redirect(lutok::state& state, tree& out_tree)
{
lutok::stack_cleaner cleaner(state);
state.new_table();
state.get_global_table();
{
state.push_string("__index");
state.push_cxx_function(redirect_index);
@ -263,11 +268,13 @@ config::redirect(lutok::state& state, tree& out_tree)
state.push_string("__newindex");
state.push_cxx_function(redirect_newindex);
state.set_table(-3);
state.push_string("tree");
config::tree** tree = state.new_userdata< config::tree* >();
*tree = &out_tree;
state.set_table(-3);
}
state.set_metatable(lutok::globals_index);
state.set_metatable(-1);
state.push_value(lutok::registry_index);
state.push_string("tree");
config::tree** tree = state.new_userdata< config::tree* >();
*tree = &out_tree;
state.set_table(-3);
state.pop(1);
}

View File

@ -34,12 +34,12 @@
#include <map>
#include <string>
#include <tr1/memory>
#include <lutok/state.hpp>
#include "utils/config/keys.hpp"
#include "utils/config/nodes.hpp"
#include "utils/shared_ptr.hpp"
namespace utils {
namespace config {
@ -82,7 +82,7 @@ typedef std::map< std::string, std::string > properties_map;
/// deep_copy().
class tree {
/// The root of the tree.
std::tr1::shared_ptr< detail::static_inner_node > _root;
std::shared_ptr< detail::static_inner_node > _root;
explicit tree(detail::static_inner_node*);

View File

@ -183,7 +183,7 @@ struct timestamp::impl {
/// Constructs a new timestamp.
///
/// \param pimpl_ An existing impl representation.
datetime::timestamp::timestamp(std::tr1::shared_ptr< impl > pimpl_) :
datetime::timestamp::timestamp(std::shared_ptr< impl > pimpl_) :
_pimpl(pimpl_)
{
}
@ -201,7 +201,7 @@ datetime::timestamp::from_microseconds(const int64_t value)
::timeval data;
data.tv_sec = static_cast< time_t >(value / 1000000);
data.tv_usec = static_cast< suseconds_t >(value % 1000000);
return timestamp(std::tr1::shared_ptr< impl >(new impl(data)));
return timestamp(std::shared_ptr< impl >(new impl(data)));
}
@ -257,7 +257,7 @@ datetime::timestamp::from_values(const int year, const int month,
::timeval data;
data.tv_sec = ::mktime(&timedata);
data.tv_usec = static_cast< suseconds_t >(microsecond);
return timestamp(std::tr1::shared_ptr< impl >(new impl(data)));
return timestamp(std::shared_ptr< impl >(new impl(data)));
}
@ -276,7 +276,7 @@ datetime::timestamp::now(void)
INV(ret != -1);
}
return timestamp(std::tr1::shared_ptr< impl >(new impl(data)));
return timestamp(std::shared_ptr< impl >(new impl(data)));
}

View File

@ -40,14 +40,15 @@ extern "C" {
#include <ostream>
#include <string>
#include <tr1/memory>
#include "utils/shared_ptr.hpp"
namespace utils {
namespace datetime {
/// Represents a time delta to describe deadlines.
struct delta {
class delta {
public:
/// The amount of seconds in the time delta.
int64_t seconds;
@ -81,9 +82,9 @@ class timestamp {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
timestamp(std::tr1::shared_ptr< impl >);
timestamp(std::shared_ptr< impl >);
public:
static timestamp from_microseconds(const int64_t);

View File

@ -33,6 +33,7 @@
#define UTILS_FORMAT_EXCEPTIONS_HPP
#include <stdexcept>
#include <string>
namespace utils {
namespace format {

View File

@ -33,9 +33,9 @@
#define UTILS_FS_AUTO_CLEANERS_HPP
#include <string>
#include <tr1/memory>
#include "utils/fs/path.hpp"
#include "utils/shared_ptr.hpp"
namespace utils {
namespace fs {
@ -48,7 +48,7 @@ namespace fs {
class auto_directory {
struct impl;
/// Reference-counted, shared implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
public:
explicit auto_directory(const path&);
@ -68,7 +68,7 @@ public:
class auto_file {
struct impl;
/// Reference-counted, shared implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
public:
explicit auto_file(const path&);

View File

@ -33,6 +33,7 @@
#define UTILS_FS_EXCEPTIONS_HPP
#include <stdexcept>
#include <string>
namespace utils {
namespace fs {

View File

@ -40,7 +40,8 @@ namespace passwd {
/// Represents a system user.
struct user {
class user {
public:
/// The name of the user.
std::string name;

View File

@ -164,7 +164,7 @@ log_exec(const fs::path& program, const process::args_vector& args)
for (process::args_vector::const_iterator iter = args.begin();
iter != args.end(); ++iter)
plain_command += F(" %s") % *iter;
LD(F("Executing%s") % plain_command);
LD(F("Executing %s") % plain_command);
}

View File

@ -0,0 +1,46 @@
// Copyright 2013 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/// \file utils/shard_ptr.hpp
/// Compatibility header to import std::shared_ptr.
#if !defined(UTILS_SHARED_PTR_HPP)
#define UTILS_SHARED_PTR_HPP
#include <ciso646>
#if defined(_LIBCPP_VERSION) || __cplusplus >= 201103L
# include <memory>
#else
# include <tr1/memory>
namespace std {
using tr1::shared_ptr;
}
#endif
#endif // !defined(UTILS_SHARED_PTR_HPP)

View File

@ -96,16 +96,15 @@ ATF_TEST_CASE_BODY(reset__ok)
}
ATF_TEST_CASE_WITHOUT_HEAD(reset__immutable);
ATF_TEST_CASE_BODY(reset__immutable)
ATF_TEST_CASE_WITHOUT_HEAD(reset__invalid);
ATF_TEST_CASE_BODY(reset__invalid)
{
ATF_REQUIRE_THROW(signals::system_error, signals::reset(SIGKILL));
ATF_REQUIRE_THROW(signals::system_error, signals::reset(SIGSTOP));
ATF_REQUIRE_THROW(signals::system_error, signals::reset(-1));
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, reset__ok);
ATF_ADD_TEST_CASE(tcs, reset__immutable);
ATF_ADD_TEST_CASE(tcs, reset__invalid);
}

View File

@ -40,9 +40,9 @@ extern "C" {
}
#include <cstddef>
#include <tr1/memory>
#include "utils/fs/path.hpp"
#include "utils/shared_ptr.hpp"
namespace utils {
namespace sqlite {
@ -79,7 +79,7 @@ class database {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
friend class database_c_gate;
database(void*, const bool);

View File

@ -40,7 +40,8 @@ extern "C" {
}
#include <string>
#include <tr1/memory>
#include "utils/shared_ptr.hpp"
namespace utils {
namespace sqlite {
@ -92,7 +93,7 @@ class statement {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
statement(database&, void*);
friend class database;

View File

@ -32,7 +32,7 @@
#if !defined(UTILS_SQLITE_TRANSACTION_HPP)
#define UTILS_SQLITE_TRANSACTION_HPP
#include <tr1/memory>
#include "utils/shared_ptr.hpp"
namespace utils {
namespace sqlite {
@ -49,7 +49,7 @@ class transaction {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
std::shared_ptr< impl > _pimpl;
explicit transaction(database&);
friend class database;

View File

@ -143,13 +143,13 @@ units::bytes::operator uint64_t(void) const
///
/// \post The bad bit of input is set to 1 if the parsing failed.
std::istream&
operator>>(std::istream& input, units::bytes& rhs)
units::operator>>(std::istream& input, bytes& rhs)
{
std::string word;
input >> word;
if (input.good() || input.eof()) {
try {
rhs = units::bytes::parse(word);
rhs = bytes::parse(word);
} catch (const std::runtime_error& e) {
input.setstate(std::ios::badbit);
}
@ -166,7 +166,7 @@ operator>>(std::istream& input, units::bytes& rhs)
///
/// \return The output stream.
std::ostream&
operator<<(std::ostream& output, const units::bytes& rhs)
units::operator<<(std::ostream& output, const bytes& rhs)
{
return (output << rhs.format());
}

View File

@ -84,10 +84,11 @@ public:
};
std::istream& operator>>(std::istream&, bytes&);
std::ostream& operator<<(std::ostream&, const bytes&);
} // namespace units
} // namespace utils
std::istream& operator>>(std::istream&, utils::units::bytes&);
std::ostream& operator<<(std::ostream&, const utils::units::bytes&);
#endif // !defined(UTILS_UNITS_HPP)