Importing NetBSD "Kyua" test framework

To do so, a few dependencies have been imported:

 * external/bsd/lutok
 * external/mit/lua
 * external/public-domain/sqlite
 * external/public-domain/xz

The Kyua framework is the new generation of ATF (Automated Test
Framework), it is composed of:

 * external/bsd/atf
 * external/bsd/kyua-atf-compat
 * external/bsd/kyua-cli
 * external/bsd/kyua-tester
 * tests

Kyua/ATF being written in C++, it depends on libstdc++ which is
provided by GCC. As this is not part of the sources, Kyua is only
compiled when the native GCC utils are installed.

To install Kyua do the following:

 * In a cross-build enviromnent, add the following to the build.sh
   commandline: -V MKBINUTILS=yes -V MKGCCCMDS=yes

WARNING:
  At this point the import is still experimental, and not supported
  on native builds (a.k.a make build).

Change-Id: I26aee23c5bbd2d64adcb7c1beb98fe0d479d7ada
This commit is contained in:
2013-07-23 20:43:41 +02:00
committed by Gerrit Code Review
parent 003ff52ebb
commit 11be35a165
2893 changed files with 502052 additions and 2630 deletions
+6
View File
@@ -0,0 +1,6 @@
syntax(2)
test_suite("kyua")
atf_test_program{name="exceptions_test"}
atf_test_program{name="formatter_test"}
+110
View File
@@ -0,0 +1,110 @@
// Copyright 2010 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.
#include "utils/format/exceptions.hpp"
using utils::format::bad_format_error;
using utils::format::error;
using utils::format::extra_args_error;
/// Constructs a new error with a plain-text message.
///
/// \param message The plain-text error message.
error::error(const std::string& message) :
std::runtime_error(message)
{
}
/// Destructor for the error.
error::~error(void) throw()
{
}
/// Constructs a new bad_format_error.
///
/// \param format_ The invalid format string.
/// \param message Description of the error in the format string.
bad_format_error::bad_format_error(const std::string& format_,
const std::string& message) :
error("Invalid formatting string '" + format_ + "': " + message),
_format(format_)
{
}
/// Destructor for the error.
bad_format_error::~bad_format_error(void) throw()
{
}
/// Gets the invalid format string.
const std::string&
bad_format_error::format(void) const
{
return _format;
}
/// Constructs a new extra_args_error.
///
/// \param format_ The format string.
/// \param arg_ The first extra argument passed to the format string.
extra_args_error::extra_args_error(const std::string& format_,
const std::string& arg_) :
error("Not enough fields in formatting string '" + format_ + "' to place "
"argument '" + arg_ + "'"),
_format(format_),
_arg(arg_)
{
}
/// Destructor for the error.
extra_args_error::~extra_args_error(void) throw()
{
}
/// Gets the format string.
const std::string&
extra_args_error::format(void) const
{
return _format;
}
/// Gets the value of the first extra argument.
const std::string&
extra_args_error::arg(void) const
{
return _arg;
}
+83
View File
@@ -0,0 +1,83 @@
// Copyright 2010 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/format/exceptions.hpp
/// Exception types raised by the format module.
#if !defined(UTILS_FORMAT_EXCEPTIONS_HPP)
#define UTILS_FORMAT_EXCEPTIONS_HPP
#include <stdexcept>
namespace utils {
namespace format {
/// Base exception for format errors.
class error : public std::runtime_error {
public:
explicit error(const std::string&);
virtual ~error(void) throw();
};
/// Error denoting a bad format string.
class bad_format_error : public error {
/// The format string that caused the error.
std::string _format;
public:
explicit bad_format_error(const std::string&, const std::string&);
virtual ~bad_format_error(void) throw();
const std::string& format(void) const;
};
/// Error denoting too many arguments for the format string.
class extra_args_error : public error {
/// The format string that was passed too many arguments.
std::string _format;
/// The first argument that caused the error.
std::string _arg;
public:
explicit extra_args_error(const std::string&, const std::string&);
virtual ~extra_args_error(void) throw();
const std::string& format(void) const;
const std::string& arg(void) const;
};
} // namespace format
} // namespace utils
#endif // !defined(UTILS_FORMAT_EXCEPTIONS_HPP)
@@ -0,0 +1,74 @@
// Copyright 2010 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.
#include "utils/format/exceptions.hpp"
#include <cstring>
#include <atf-c++.hpp>
using utils::format::bad_format_error;
using utils::format::error;
using utils::format::extra_args_error;
ATF_TEST_CASE_WITHOUT_HEAD(error);
ATF_TEST_CASE_BODY(error)
{
const error e("Some text");
ATF_REQUIRE(std::strcmp("Some text", e.what()) == 0);
}
ATF_TEST_CASE_WITHOUT_HEAD(bad_format_error);
ATF_TEST_CASE_BODY(bad_format_error)
{
const bad_format_error e("format-string", "the-error");
ATF_REQUIRE(std::strcmp("Invalid formatting string 'format-string': "
"the-error", e.what()) == 0);
ATF_REQUIRE_EQ("format-string", e.format());
}
ATF_TEST_CASE_WITHOUT_HEAD(extra_args_error);
ATF_TEST_CASE_BODY(extra_args_error)
{
const extra_args_error e("fmt", "extra");
ATF_REQUIRE(std::strcmp("Not enough fields in formatting string 'fmt' to "
"place argument 'extra'", e.what()) == 0);
ATF_REQUIRE_EQ("fmt", e.format());
ATF_REQUIRE_EQ("extra", e.arg());
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, error);
ATF_ADD_TEST_CASE(tcs, bad_format_error);
ATF_ADD_TEST_CASE(tcs, extra_args_error);
}
+291
View File
@@ -0,0 +1,291 @@
// Copyright 2010 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.
#include "utils/format/formatter.hpp"
#include <memory>
#include <string>
#include <utility>
#include "utils/format/exceptions.hpp"
#include "utils/sanity.hpp"
#include "utils/text/exceptions.hpp"
#include "utils/text/operations.ipp"
namespace format = utils::format;
namespace text = utils::text;
namespace {
/// Finds the next placeholder in a string.
///
/// \param format The original format string provided by the user; needed for
/// error reporting purposes only.
/// \param expansion The string containing the placeholder to look for. Any
/// '%%' in the string will be skipped, and they must be stripped later by
/// strip_double_percent().
/// \param begin The position from which to start looking for the next
/// placeholder.
///
/// \return The position in the string in which the placeholder is located and
/// the placeholder itself. If there are no placeholders left, this returns
/// the length of the string and an empty string.
///
/// \throw bad_format_error If the input string contains a trailing formatting
/// character. We cannot detect any other kind of invalid formatter because
/// we do not implement a full parser for them.
static std::pair< std::string::size_type, std::string >
find_next_placeholder(const std::string& format,
const std::string& expansion,
std::string::size_type begin)
{
begin = expansion.find('%', begin);
while (begin != std::string::npos && expansion[begin + 1] == '%')
begin = expansion.find('%', begin + 2);
if (begin == std::string::npos)
return std::make_pair(expansion.length(), "");
if (begin == expansion.length() - 1)
throw format::bad_format_error(format, "Trailing %");
std::string::size_type end = begin + 1;
while (end < expansion.length() && expansion[end] != 's')
end++;
const std::string placeholder = expansion.substr(begin, end - begin + 1);
if (end == expansion.length() ||
placeholder.find('%', 1) != std::string::npos)
throw format::bad_format_error(format, "Unterminated placeholder '" +
placeholder + "'");
return std::make_pair(begin, placeholder);
}
/// Converts a string to an integer.
///
/// \param format The format string; for error reporting purposes only.
/// \param str The string to conver.
/// \param what The name of the field this integer belongs to; for error
/// reporting purposes only.
///
/// \return An integer representing the input string.
inline int
to_int(const std::string& format, const std::string& str, const char* what)
{
try {
return text::to_type< int >(str);
} catch (const text::value_error& e) {
throw format::bad_format_error(format, "Invalid " + std::string(what) +
"specifier");
}
}
/// Constructs an std::ostringstream based on a formatting placeholder.
///
/// \param format The format placeholder; may be empty.
///
/// \return A new std::ostringstream that is prepared to format a single
/// object in the manner specified by the format placeholder.
///
/// \throw bad_format_error If the format string is bad. We do minimal
/// validation on this string though.
static std::ostringstream*
new_ostringstream(const std::string& format)
{
std::auto_ptr< std::ostringstream > output(new std::ostringstream());
if (format.length() <= 2) {
// If the format is empty, we create a new stream so that we don't have
// to check for NULLs later on. We rarely should hit this condition
// (and when we do it's a bug in the caller), so this is not a big deal.
//
// Otherwise, if the format is a regular '%s', then we don't have to do
// any processing for additional formatters. So this is just a "fast
// path".
} else {
std::string partial = format.substr(1, format.length() - 2);
if (partial[0] == '0') {
output->fill('0');
partial.erase(0, 1);
}
if (!partial.empty()) {
const std::string::size_type dot = partial.find('.');
if (dot != 0)
output->width(to_int(format, partial.substr(0, dot), "width"));
if (dot != std::string::npos) {
output->setf(std::ios::fixed, std::ios::floatfield);
output->precision(to_int(format, partial.substr(dot + 1),
"precision"));
}
}
}
return output.release();
}
/// Replaces '%%' by '%' in a given string range.
///
/// \param in The input string to be rewritten.
/// \param begin The position at which to start the replacement.
/// \param end The position at which to end the replacement.
///
/// \return The modified string and the amount of characters removed.
static std::pair< std::string, int >
strip_double_percent(const std::string& in, const std::string::size_type begin,
std::string::size_type end)
{
std::string part = in.substr(begin, end - begin);
int removed = 0;
std::string::size_type pos = part.find("%%");
while (pos != std::string::npos) {
part.erase(pos, 1);
++removed;
pos = part.find("%%", pos + 1);
}
return std::make_pair(in.substr(0, begin) + part + in.substr(end), removed);
}
} // anonymous namespace
/// Performs internal initialization of the formatter.
///
/// This is separate from the constructor just because it is shared by different
/// overloaded constructors.
void
format::formatter::init(void)
{
const std::pair< std::string::size_type, std::string > placeholder =
find_next_placeholder(_format, _expansion, _last_pos);
const std::pair< std::string, int > no_percents =
strip_double_percent(_expansion, _last_pos, placeholder.first);
_oss = new_ostringstream(placeholder.second);
_expansion = no_percents.first;
_placeholder_pos = placeholder.first - no_percents.second;
_placeholder = placeholder.second;
}
/// Constructs a new formatter object (internal).
///
/// \param format The format string.
/// \param expansion The format string with any replacements performed so far.
/// \param last_pos The position from which to start looking for formatting
/// placeholders. This must be maintained in case one of the replacements
/// introduced a new placeholder, which must be ignored. Think, for
/// example, replacing a "%s" string with "foo %s".
format::formatter::formatter(const std::string& format,
const std::string& expansion,
const std::string::size_type last_pos) :
_format(format),
_expansion(expansion),
_last_pos(last_pos),
_oss(NULL)
{
init();
}
/// Constructs a new formatter object.
///
/// \param format The format string. The formatters in the string are not
/// validated during construction, but will cause errors when used later if
/// they are invalid.
format::formatter::formatter(const std::string& format) :
_format(format),
_expansion(format),
_last_pos(0),
_oss(NULL)
{
init();
}
format::formatter::~formatter(void)
{
delete _oss;
}
/// Returns the formatted string.
const std::string&
format::formatter::str(void) const
{
return _expansion;
}
/// Automatic conversion of formatter objects to strings.
///
/// This is provided to allow painless injection of formatter objects into
/// streams, without having to manually call the str() method.
format::formatter::operator const std::string&(void) const
{
return _expansion;
}
/// Specialization of operator% for booleans.
///
/// \param value The boolean to inject into the format string.
///
/// \return A new formatter that has one less format placeholder.
format::formatter
format::formatter::operator%(const bool& value) const
{
(*_oss) << (value ? "true" : "false");
return replace(_oss->str());
}
/// Replaces the first formatting placeholder with a value.
///
/// \param arg The replacement string.
///
/// \return A new formatter in which the first formatting placeholder has been
/// replaced by arg and is ready to replace the next item.
///
/// \throw utils::format::extra_args_error If there are no more formatting
/// placeholders in the input string, or if the placeholder is invalid.
format::formatter
format::formatter::replace(const std::string& arg) const
{
if (_placeholder_pos == _expansion.length())
throw format::extra_args_error(_format, arg);
const std::string expansion = _expansion.substr(0, _placeholder_pos)
+ arg + _expansion.substr(_placeholder_pos + _placeholder.length());
return formatter(_format, expansion, _placeholder_pos + arg.length());
}
+121
View File
@@ -0,0 +1,121 @@
// Copyright 2010 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/format/formatter.hpp
/// Provides the definition of the utils::format::formatter class.
///
/// The utils::format::formatter class is a poor man's replacement for the
/// Boost.Format library, as it is much simpler and has less dependencies.
///
/// Be aware that the formatting supported by this module is NOT compatible
/// with printf(3) nor with Boost.Format. The general syntax for a
/// placeholder in a formatting string is:
///
/// %[0][width][.precision]s
///
/// In particular, note that the only valid formatting specifier is %s: the
/// library deduces what to print based on the type of the variable passed
/// in, not based on what the format string says. Also, note that the only
/// valid padding character is 0.
#if !defined(UTILS_FORMAT_FORMATTER_HPP)
#define UTILS_FORMAT_FORMATTER_HPP
#include <sstream>
#include <string>
namespace utils {
namespace format {
/// Mechanism to format strings similar to printf.
///
/// A formatter always maintains the original format string but also holds a
/// partial expansion. The partial expansion is immutable in the context of a
/// formatter instance, but calls to operator% return new formatter objects with
/// one less formatting placeholder.
///
/// In general, one can format a string in the following manner:
///
/// \code
/// const std::string s = (formatter("%s %s") % "foo" % 5).str();
/// \endcode
///
/// which, following the explanation above, would correspond to:
///
/// \code
/// const formatter f1("%s %s");
/// const formatter f2 = f1 % "foo";
/// const formatter f3 = f2 % 5;
/// const std::string s = f3.str();
/// \endcode
class formatter {
/// The original format string provided by the user.
std::string _format;
/// The current "expansion" of the format string.
///
/// This field gets updated on every call to operator%() to have one less
/// formatting placeholder.
std::string _expansion;
/// The position of _expansion from which to scan for placeholders.
std::string::size_type _last_pos;
/// The position of the first placeholder in the current expansion.
std::string::size_type _placeholder_pos;
/// The first placeholder in the current expansion.
std::string _placeholder;
/// Stream used to format any possible argument supplied by operator%().
std::ostringstream* _oss;
formatter replace(const std::string&) const;
void init(void);
formatter(const std::string&, const std::string&,
const std::string::size_type);
public:
explicit formatter(const std::string&);
~formatter(void);
const std::string& str(void) const;
operator const std::string&(void) const;
template< typename Type > formatter operator%(const Type&) const;
formatter operator%(const bool&) const;
};
} // namespace format
} // namespace utils
#endif // !defined(UTILS_FORMAT_FORMATTER_HPP)
+76
View File
@@ -0,0 +1,76 @@
// Copyright 2010 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.
#if !defined(UTILS_FORMAT_FORMATTER_IPP)
#define UTILS_FORMAT_FORMATTER_IPP
#include <ostream>
#include "utils/format/formatter.hpp"
namespace utils {
namespace format {
/// Replaces the first format placeholder in a formatter.
///
/// Constructs a new formatter object that has one less formatting placeholder,
/// as this has been replaced by the provided argument. Calling this operator
/// N times, where N is the number of formatting placeholders, effectively
/// formats the string.
///
/// \param arg The argument to use as replacement for the format placeholder.
///
/// \return A new formatter that has one less format placeholder.
template< typename Type >
inline formatter
formatter::operator%(const Type& arg) const
{
(*_oss) << arg;
return replace(_oss->str());
}
/// Inserts a formatter string into a stream.
///
/// \param os The output stream.
/// \param f The formatter to process and inject into the stream.
///
/// \return The output stream os.
inline std::ostream&
operator<<(std::ostream& os, const formatter& f)
{
return (os << f.str());
}
} // namespace format
} // namespace utils
#endif // !defined(UTILS_FORMAT_FORMATTER_IPP)
@@ -0,0 +1,265 @@
// Copyright 2010 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.
#include "utils/format/formatter.hpp"
#include <ostream>
#include <atf-c++.hpp>
#include "utils/format/exceptions.hpp"
#include "utils/format/macros.hpp"
namespace format = utils::format;
namespace {
/// Wraps an integer in a C++ class.
///
/// This custom type exists to ensure that we can feed arbitrary objects that
/// support operator<< to the formatter;
class int_wrapper {
/// The wrapped integer.
int _value;
public:
/// Constructs a new wrapper.
///
/// \param value_ The value to wrap.
int_wrapper(const int value_) : _value(value_)
{
}
/// Returns the wrapped value.
///
/// \return An integer.
int
value(void) const
{
return _value;
}
};
/// Writes a wrapped integer into an output stream.
///
/// \param output The output stream into which to place the integer.
/// \param wrapper The wrapped integer.
///
/// \return The output stream.
std::ostream&
operator<<(std::ostream& output, const int_wrapper& wrapper)
{
return (output << wrapper.value());
}
} // anonymous namespace
/// Calls ATF_REQUIRE_EQ on an expected string and a formatter.
///
/// This is pure syntactic sugar to avoid calling the str() method on all the
/// individual tests below, which results in very long lines that require
/// wrapping and clutter readability.
///
/// \param expected The expected string generated by the formatter.
/// \param formatter The formatter to test.
#define EQ(expected, formatter) ATF_REQUIRE_EQ(expected, (formatter).str())
ATF_TEST_CASE_WITHOUT_HEAD(no_fields);
ATF_TEST_CASE_BODY(no_fields)
{
EQ("Plain string", F("Plain string"));
}
ATF_TEST_CASE_WITHOUT_HEAD(one_field);
ATF_TEST_CASE_BODY(one_field)
{
EQ("foo", F("%sfoo") % "");
EQ(" foo", F("%sfoo") % " ");
EQ("foo ", F("foo %s") % "");
EQ("foo bar", F("foo %s") % "bar");
EQ("foo bar baz", F("foo %s baz") % "bar");
EQ("foo %s %s", F("foo %s %s") % "%s" % "%s");
}
ATF_TEST_CASE_WITHOUT_HEAD(many_fields);
ATF_TEST_CASE_BODY(many_fields)
{
EQ("", F("%s%s") % "" % "");
EQ("foo", F("%s%s%s") % "" % "foo" % "");
EQ("some 5 text", F("%s %s %s") % "some" % 5 % "text");
EQ("f%s 5 text", F("%s %s %s") % "f%s" % 5 % "text");
}
ATF_TEST_CASE_WITHOUT_HEAD(escape);
ATF_TEST_CASE_BODY(escape)
{
EQ("%", F("%%"));
EQ("% %", F("%% %%"));
EQ("%% %%", F("%%%% %%%%"));
EQ("foo %", F("foo %%"));
EQ("foo bar %", F("foo %s %%") % "bar");
EQ("foo % bar", F("foo %% %s") % "bar");
EQ("foo %%", F("foo %s") % "%%");
EQ("foo a%%b", F("foo a%sb") % "%%");
EQ("foo a%%b", F("foo %s") % "a%%b");
EQ("foo % bar %%", F("foo %% %s %%%%") % "bar");
}
ATF_TEST_CASE_WITHOUT_HEAD(extra_args_error);
ATF_TEST_CASE_BODY(extra_args_error)
{
using format::extra_args_error;
ATF_REQUIRE_THROW(extra_args_error, F("foo") % "bar");
ATF_REQUIRE_THROW(extra_args_error, F("foo %%") % "bar");
ATF_REQUIRE_THROW(extra_args_error, F("foo %s") % "bar" % "baz");
ATF_REQUIRE_THROW(extra_args_error, F("foo %s") % "%s" % "bar");
ATF_REQUIRE_THROW(extra_args_error, F("%s foo %s") % "bar" % "baz" % "foo");
try {
F("foo %s %s") % "bar" % "baz" % "something extra";
fail("extra_args_error not raised");
} catch (const extra_args_error& e) {
ATF_REQUIRE_EQ("foo %s %s", e.format());
ATF_REQUIRE_EQ("something extra", e.arg());
}
}
ATF_TEST_CASE_WITHOUT_HEAD(format__class);
ATF_TEST_CASE_BODY(format__class)
{
EQ("foo bar", F("%s") % std::string("foo bar"));
EQ("3", F("%s") % int_wrapper(3));
}
ATF_TEST_CASE_WITHOUT_HEAD(format__pointer);
ATF_TEST_CASE_BODY(format__pointer)
{
EQ("0xcafebabe", F("%s") % reinterpret_cast< void* >(0xcafebabe));
EQ("foo bar", F("%s") % "foo bar");
}
ATF_TEST_CASE_WITHOUT_HEAD(format__bool);
ATF_TEST_CASE_BODY(format__bool)
{
EQ("true", F("%s") % true);
EQ("false", F("%s") % false);
}
ATF_TEST_CASE_WITHOUT_HEAD(format__char);
ATF_TEST_CASE_BODY(format__char)
{
EQ("Z", F("%s") % 'Z');
}
ATF_TEST_CASE_WITHOUT_HEAD(format__float);
ATF_TEST_CASE_BODY(format__float)
{
EQ("3", F("%s") % 3.0);
EQ("3.0", F("%.1s") % 3.0);
EQ("3.0", F("%0.1s") % 3.0);
EQ(" 15.600", F("%8.3s") % 15.6);
EQ("01.52", F("%05.2s") % 1.52);
}
ATF_TEST_CASE_WITHOUT_HEAD(format__int);
ATF_TEST_CASE_BODY(format__int)
{
EQ("3", F("%s") % 3);
EQ("3", F("%0s") % 3);
EQ(" -123", F("%5s") % -123);
EQ("00078", F("%05s") % 78);
}
ATF_TEST_CASE_WITHOUT_HEAD(format__error);
ATF_TEST_CASE_BODY(format__error)
{
using format::bad_format_error;
ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("%"));
ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("f%"));
ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("f%%%"));
ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("ab %s cd%") % "cd");
ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid width", F("%1bs"));
ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%.s"));
ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%0.s"));
ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%123.s"));
ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%.12bs"));
ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%c") % 'Z');
ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%d") % 5);
ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%.1f") % 3);
ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%d%s") % 3 % "a");
try {
F("foo %s%") % "bar";
fail("bad_format_error not raised");
} catch (const bad_format_error& e) {
ATF_REQUIRE_EQ("foo %s%", e.format());
}
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, no_fields);
ATF_ADD_TEST_CASE(tcs, one_field);
ATF_ADD_TEST_CASE(tcs, many_fields);
ATF_ADD_TEST_CASE(tcs, escape);
ATF_ADD_TEST_CASE(tcs, extra_args_error);
ATF_ADD_TEST_CASE(tcs, format__class);
ATF_ADD_TEST_CASE(tcs, format__pointer);
ATF_ADD_TEST_CASE(tcs, format__bool);
ATF_ADD_TEST_CASE(tcs, format__char);
ATF_ADD_TEST_CASE(tcs, format__float);
ATF_ADD_TEST_CASE(tcs, format__int);
ATF_ADD_TEST_CASE(tcs, format__error);
}
+58
View File
@@ -0,0 +1,58 @@
// Copyright 2010 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/format/macros.hpp
/// Convenience macros to simplify usage of the format library.
///
/// This file <em>must not be included from other header files</em>.
#if !defined(UTILS_FORMAT_MACROS_HPP)
#define UTILS_FORMAT_MACROS_HPP
// We include the .ipp file instead of .hpp because, after all, macros.hpp
// is provided purely for convenience and must not be included from other
// header files. Henceforth, we make things easier to the callers.
#include "utils/format/formatter.ipp"
/// Constructs a utils::format::formatter object with the given format string.
///
/// This macro is just a wrapper to make the construction of
/// utils::format::formatter objects shorter, and thus to allow inlining these
/// calls right in where formatted strings are required. A typical usage would
/// look like:
///
/// \code
/// std::cout << F("%s %d\n") % my_str % my_int;
/// \endcode
///
/// \param fmt The format string.
#define F(fmt) utils::format::formatter(fmt)
#endif // !defined(UTILS_FORMAT_MACROS_HPP)