Path: blob/main/contrib/kyua/utils/format/formatter_test.cpp
48178 views
// Copyright 2010 The Kyua Authors.1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are5// met:6//7// * Redistributions of source code must retain the above copyright8// notice, this list of conditions and the following disclaimer.9// * Redistributions in binary form must reproduce the above copyright10// notice, this list of conditions and the following disclaimer in the11// documentation and/or other materials provided with the distribution.12// * Neither the name of Google Inc. nor the names of its contributors13// may be used to endorse or promote products derived from this software14// without specific prior written permission.15//16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2728#include "utils/format/formatter.hpp"2930#include <ostream>3132#include <atf-c++.hpp>3334#include "utils/format/exceptions.hpp"35#include "utils/format/macros.hpp"3637namespace format = utils::format;383940namespace {414243/// Wraps an integer in a C++ class.44///45/// This custom type exists to ensure that we can feed arbitrary objects that46/// support operator<< to the formatter;47class int_wrapper {48/// The wrapped integer.49int _value;5051public:52/// Constructs a new wrapper.53///54/// \param value_ The value to wrap.55int_wrapper(const int value_) : _value(value_)56{57}5859/// Returns the wrapped value.60///61/// \return An integer.62int63value(void) const64{65return _value;66}67};686970/// Writes a wrapped integer into an output stream.71///72/// \param output The output stream into which to place the integer.73/// \param wrapper The wrapped integer.74///75/// \return The output stream.76std::ostream&77operator<<(std::ostream& output, const int_wrapper& wrapper)78{79return (output << wrapper.value());80}818283} // anonymous namespace848586/// Calls ATF_REQUIRE_EQ on an expected string and a formatter.87///88/// This is pure syntactic sugar to avoid calling the str() method on all the89/// individual tests below, which results in very long lines that require90/// wrapping and clutter readability.91///92/// \param expected The expected string generated by the formatter.93/// \param formatter The formatter to test.94#define EQ(expected, formatter) ATF_REQUIRE_EQ(expected, (formatter).str())959697ATF_TEST_CASE_WITHOUT_HEAD(no_fields);98ATF_TEST_CASE_BODY(no_fields)99{100EQ("Plain string", F("Plain string"));101}102103104ATF_TEST_CASE_WITHOUT_HEAD(one_field);105ATF_TEST_CASE_BODY(one_field)106{107EQ("foo", F("%sfoo") % "");108EQ(" foo", F("%sfoo") % " ");109EQ("foo ", F("foo %s") % "");110EQ("foo bar", F("foo %s") % "bar");111EQ("foo bar baz", F("foo %s baz") % "bar");112EQ("foo %s %s", F("foo %s %s") % "%s" % "%s");113}114115116ATF_TEST_CASE_WITHOUT_HEAD(many_fields);117ATF_TEST_CASE_BODY(many_fields)118{119EQ("", F("%s%s") % "" % "");120EQ("foo", F("%s%s%s") % "" % "foo" % "");121EQ("some 5 text", F("%s %s %s") % "some" % 5 % "text");122EQ("f%s 5 text", F("%s %s %s") % "f%s" % 5 % "text");123}124125126ATF_TEST_CASE_WITHOUT_HEAD(escape);127ATF_TEST_CASE_BODY(escape)128{129EQ("%", F("%%"));130EQ("% %", F("%% %%"));131EQ("%% %%", F("%%%% %%%%"));132133EQ("foo %", F("foo %%"));134EQ("foo bar %", F("foo %s %%") % "bar");135EQ("foo % bar", F("foo %% %s") % "bar");136137EQ("foo %%", F("foo %s") % "%%");138EQ("foo a%%b", F("foo a%sb") % "%%");139EQ("foo a%%b", F("foo %s") % "a%%b");140141EQ("foo % bar %%", F("foo %% %s %%%%") % "bar");142}143144145ATF_TEST_CASE_WITHOUT_HEAD(extra_args_error);146ATF_TEST_CASE_BODY(extra_args_error)147{148using format::extra_args_error;149150ATF_REQUIRE_THROW(extra_args_error, F("foo") % "bar");151ATF_REQUIRE_THROW(extra_args_error, F("foo %%") % "bar");152ATF_REQUIRE_THROW(extra_args_error, F("foo %s") % "bar" % "baz");153ATF_REQUIRE_THROW(extra_args_error, F("foo %s") % "%s" % "bar");154ATF_REQUIRE_THROW(extra_args_error, F("%s foo %s") % "bar" % "baz" % "foo");155156try {157F("foo %s %s") % "bar" % "baz" % "something extra";158fail("extra_args_error not raised");159} catch (const extra_args_error& e) {160ATF_REQUIRE_EQ("foo %s %s", e.format());161ATF_REQUIRE_EQ("something extra", e.arg());162}163}164165166ATF_TEST_CASE_WITHOUT_HEAD(format__class);167ATF_TEST_CASE_BODY(format__class)168{169EQ("foo bar", F("%s") % std::string("foo bar"));170EQ("3", F("%s") % int_wrapper(3));171}172173174ATF_TEST_CASE_WITHOUT_HEAD(format__pointer);175ATF_TEST_CASE_BODY(format__pointer)176{177EQ("0xcafebabe", F("%s") % reinterpret_cast< void* >(0xcafebabe));178EQ("foo bar", F("%s") % "foo bar");179}180181182ATF_TEST_CASE_WITHOUT_HEAD(format__bool);183ATF_TEST_CASE_BODY(format__bool)184{185EQ("true", F("%s") % true);186EQ("false", F("%s") % false);187}188189190ATF_TEST_CASE_WITHOUT_HEAD(format__char);191ATF_TEST_CASE_BODY(format__char)192{193EQ("Z", F("%s") % 'Z');194}195196197ATF_TEST_CASE_WITHOUT_HEAD(format__float);198ATF_TEST_CASE_BODY(format__float)199{200EQ("3", F("%s") % 3.0);201EQ("3.0", F("%.1s") % 3.0);202EQ("3.0", F("%0.1s") % 3.0);203EQ(" 15.600", F("%8.3s") % 15.6);204EQ("01.52", F("%05.2s") % 1.52);205}206207208ATF_TEST_CASE_WITHOUT_HEAD(format__int);209ATF_TEST_CASE_BODY(format__int)210{211EQ("3", F("%s") % 3);212EQ("3", F("%0s") % 3);213EQ(" -123", F("%5s") % -123);214EQ("00078", F("%05s") % 78);215}216217218ATF_TEST_CASE_WITHOUT_HEAD(format__error);219ATF_TEST_CASE_BODY(format__error)220{221using format::bad_format_error;222223ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("%"));224ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("f%"));225ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("f%%%"));226ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("ab %s cd%") % "cd");227228ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid width", F("%1bs"));229230ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%.s"));231ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%0.s"));232ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%123.s"));233ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%.12bs"));234235ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%c") % 'Z');236ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%d") % 5);237ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%.1f") % 3);238ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%d%s") % 3 % "a");239240try {241F("foo %s%") % "bar";242fail("bad_format_error not raised");243} catch (const bad_format_error& e) {244ATF_REQUIRE_EQ("foo %s%", e.format());245}246}247248249ATF_INIT_TEST_CASES(tcs)250{251ATF_ADD_TEST_CASE(tcs, no_fields);252ATF_ADD_TEST_CASE(tcs, one_field);253ATF_ADD_TEST_CASE(tcs, many_fields);254ATF_ADD_TEST_CASE(tcs, escape);255ATF_ADD_TEST_CASE(tcs, extra_args_error);256257ATF_ADD_TEST_CASE(tcs, format__class);258ATF_ADD_TEST_CASE(tcs, format__pointer);259ATF_ADD_TEST_CASE(tcs, format__bool);260ATF_ADD_TEST_CASE(tcs, format__char);261ATF_ADD_TEST_CASE(tcs, format__float);262ATF_ADD_TEST_CASE(tcs, format__int);263ATF_ADD_TEST_CASE(tcs, format__error);264}265266267