Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
fmt
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
fmt
Commits
41fbaeb3
Commit
41fbaeb3
authored
Apr 13, 2019
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add <format> test
parent
8bc0adb9
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
194 additions
and
59 deletions
+194
-59
include/fmt/format.h
include/fmt/format.h
+9
-3
include/format
include/format
+17
-55
support/cmake/cxx14.cmake
support/cmake/cxx14.cmake
+10
-0
test/CMakeLists.txt
test/CMakeLists.txt
+7
-1
test/std-format-test.cc
test/std-format-test.cc
+151
-0
No files found.
include/fmt/format.h
View file @
41fbaeb3
...
...
@@ -176,6 +176,10 @@ FMT_END_NAMESPACE
# define FMT_USE_TRAILING_RETURN 0
#endif
#ifndef FMT_USE_INT128
# define FMT_USE_INT128 (__SIZEOF_INT128__ != 0)
#endif
// __builtin_clz is broken in clang with Microsoft CodeGen:
// https://github.com/fmtlib/fmt/issues/519
#ifndef _MSC_VER
...
...
@@ -1418,7 +1422,8 @@ void arg_map<Context>::init(const basic_format_args<Context>& args) {
}
}
template
<
typename
Range
>
class
arg_formatter_base
{
template
<
typename
Range
,
typename
ErrorHandler
=
internal
::
error_handler
>
class
arg_formatter_base
{
public:
typedef
typename
Range
::
value_type
char_type
;
typedef
decltype
(
internal
::
declval
<
Range
>
().
begin
())
iterator
;
...
...
@@ -1498,7 +1503,7 @@ template <typename Range> class arg_formatter_base {
return
out
();
}
struct
char_spec_handler
:
internal
::
error_h
andler
{
struct
char_spec_handler
:
ErrorH
andler
{
arg_formatter_base
&
formatter
;
char_type
value
;
...
...
@@ -2732,7 +2737,8 @@ template <typename Range> class basic_writer {
}
};
template
<
typename
Char
>
friend
class
internal
::
arg_formatter_base
;
template
<
typename
Char
,
typename
ErrorHandler
>
friend
class
internal
::
arg_formatter_base
;
public:
/** Constructs a ``basic_writer`` object. */
...
...
include/format
View file @
41fbaeb3
...
...
@@ -17,9 +17,6 @@
// std::variant and should store packed argument type tags separately from
// values in basic_format_args for small number of arguments.
#define FMT_REQUIRES(...)
#define FMT_CONCEPT(C) typename
namespace std {
template<class T>
constexpr bool Integral = is_integral_v<T>;
...
...
@@ -117,6 +114,17 @@ namespace std {
};
}
namespace std {
namespace detail {
struct error_handler {
// This function is intentionally not constexpr to give a compile-time error.
void on_error(const char* message) {
throw std::format_error(message);
}
};
}
}
// http://fmtlib.net/Text%20Formatting.html#format.parse_context
namespace std {
template<class charT>
...
...
@@ -149,7 +157,7 @@ namespace std {
// Implementation detail:
constexpr void check_arg_id(fmt::string_view) {}
fmt::interna
l::error_handler error_handler() const { return {}; }
detai
l::error_handler error_handler() const { return {}; }
void on_error(const char* msg) { error_handler().on_error(msg); }
};
}
...
...
@@ -212,7 +220,7 @@ namespace std {
using format_arg = basic_format_arg<basic_format_context>;
basic_format_context(Out out, basic_format_args<basic_format_context> args, fmt::internal::locale_ref)
: args_(args), out_(out) {}
fmt::interna
l::error_handler error_handler() const { return {}; }
detai
l::error_handler error_handler() const { return {}; }
basic_format_arg<basic_format_context> arg(fmt::basic_string_view<charT>) const {
return {}; // unused: named arguments are not supported yet
}
...
...
@@ -482,11 +490,11 @@ namespace detail {
template <typename Range>
class arg_formatter
: public fmt::internal::function<
typename fmt::internal::arg_formatter_base<Range>::iterator>,
public fmt::internal::arg_formatter_base<Range> {
typename fmt::internal::arg_formatter_base<Range
, error_handler
>::iterator>,
public fmt::internal::arg_formatter_base<Range
, error_handler
> {
private:
using char_type = typename Range::value_type;
using base = fmt::internal::arg_formatter_base<Range>;
using base = fmt::internal::arg_formatter_base<Range
, error_handler
>;
using format_context = std::basic_format_context<typename base::iterator, char_type>;
using parse_context = basic_format_parse_context<char_type>;
...
...
@@ -574,7 +582,7 @@ class custom_formatter {
};
template <typename ArgFormatter, typename Char, typename Context>
struct format_handler :
fmt::interna
l::error_handler {
struct format_handler :
detai
l::error_handler {
typedef typename ArgFormatter::range range;
format_handler(range r, basic_string_view<Char> str,
...
...
@@ -854,50 +862,4 @@ template <> struct formatter<long double, charT> : detail::formatter<long double
};
}
inline void test0() {
using namespace std;
string s = format("{0}-{{", 8); // s == "8-{"
}
inline void test1() {
using namespace std;
string s0 = format("{} to {}", "a", "b"); // OK: automatic indexing
string s1 = format("{1} to {0}", "a", "b"); // OK: manual indexing
string s2 = format("{0} to {}", "a", "b"); // Error: mixing automatic and manual indexing
string s3 = format("{} to {1}", "a", "b"); // Error: mixing automatic and manual indexing
}
inline void test2() {
using namespace std;
char c = 120;
string s0 = format("{:6}", 42); // s0 == " 42"
string s1 = format("{:6}", 'x'); // s1 == "x "
string s2 = format("{:*<6}", 'x'); // s2 == "x*****"
string s3 = format("{:*>6}", 'x'); // s3 == "*****x"
string s4 = format("{:*^6}", 'x'); // s4 == "**x***"
string s5 = format("{:=6}", 'x'); // Error: '=' with charT and no integer presentation type
string s6 = format("{:6d}", c); // s6 == " 120"
string s7 = format("{:=+06d}", c); // s7 == "+00120"
string s8 = format("{:0=#6x}", 0xa); // s8 == "0x000a"
string s9 = format("{:6}", true); // s9 == "true "
}
inline void test3() {
using namespace std;
double inf = numeric_limits<double>::infinity();
double nan = numeric_limits<double>::quiet_NaN();
string s0 = format("{0:} {0:+} {0:-} {0: }", 1); // s0 == "1 +1 1 1"
string s1 = format("{0:} {0:+} {0:-} {0: }", -1); // s1 == "-1 -1 -1 -1"
string s2 = format("{0:} {0:+} {0:-} {0: }", inf); // s2 == "inf +inf inf inf"
string s3 = format("{0:} {0:+} {0:-} {0: }", nan); // s3 == "nan +nan nan nan"
}
inline void test4() {
using namespace std;
string s0 = format("{}", 42); // s0 == "42"
string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); // s1 == "101010 42 52 2a"
string s2 = format("{0:#x} {0:#X}", 42); // s2 == "0x2a 0X2A"
string s3 = format("{:n}", 1234); // s3 == "1,234" (depends on the locale)
}
#endif // FMT_FORMAT_
support/cmake/cxx14.cmake
View file @
41fbaeb3
...
...
@@ -68,4 +68,14 @@ if (NOT SUPPORTS_USER_DEFINED_LITERALS)
set
(
SUPPORTS_USER_DEFINED_LITERALS OFF
)
endif
()
# Check if <variant> is available
set
(
CMAKE_REQUIRED_FLAGS -std=c++1z
)
check_cxx_source_compiles
(
"
#include <variant>
int main() {}"
FMT_HAS_VARIANT
)
if
(
NOT FMT_HAS_VARIANT
)
set
(
FMT_HAS_VARIANT OFF
)
endif
()
set
(
CMAKE_REQUIRED_FLAGS
)
test/CMakeLists.txt
View file @
41fbaeb3
...
...
@@ -33,7 +33,7 @@ endif ()
# Silence MSVC tr1 deprecation warning in gmock.
target_compile_definitions
(
gmock
PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=
0
)
PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=
1
)
#------------------------------------------------------------------------------
# Build the actual library tests
...
...
@@ -99,6 +99,12 @@ add_fmt_test(printf-test)
add_fmt_test
(
custom-formatter-test
)
add_fmt_test
(
ranges-test
)
# MSVC fails to compile GMock when C++17 is enabled.
if
(
FMT_HAS_VARIANT AND NOT MSVC
)
add_fmt_test
(
std-format-test
)
set_property
(
TARGET std-format-test PROPERTY CXX_STANDARD 17
)
endif
()
if
(
HAVE_OPEN
)
add_fmt_executable
(
posix-mock-test
posix-mock-test.cc ../src/format.cc
${
TEST_MAIN_SRC
}
)
...
...
test/std-format-test.cc
0 → 100644
View file @
41fbaeb3
#include <format>
#include "gtest.h"
TEST
(
StdFormatTest
,
Escaping
)
{
using
namespace
std
;
string
s
=
format
(
"{0}-{{"
,
8
);
// s == "8-{"
EXPECT_EQ
(
s
,
"8-{"
);
}
TEST
(
StdFormatTest
,
Indexing
)
{
using
namespace
std
;
string
s0
=
format
(
"{} to {}"
,
"a"
,
"b"
);
// OK: automatic indexing
string
s1
=
format
(
"{1} to {0}"
,
"a"
,
"b"
);
// OK: manual indexing
EXPECT_EQ
(
s0
,
"a to b"
);
EXPECT_EQ
(
s1
,
"b to a"
);
// Error: mixing automatic and manual indexing
EXPECT_THROW
(
string
s2
=
format
(
"{0} to {}"
,
"a"
,
"b"
),
std
::
format_error
);
// Error: mixing automatic and manual indexing
EXPECT_THROW
(
string
s3
=
format
(
"{} to {1}"
,
"a"
,
"b"
),
std
::
format_error
);
}
TEST
(
StdFormatTest
,
Alignment
)
{
using
namespace
std
;
char
c
=
120
;
string
s0
=
format
(
"{:6}"
,
42
);
// s0 == " 42"
string
s1
=
format
(
"{:6}"
,
'x'
);
// s1 == "x "
string
s2
=
format
(
"{:*<6}"
,
'x'
);
// s2 == "x*****"
string
s3
=
format
(
"{:*>6}"
,
'x'
);
// s3 == "*****x"
string
s4
=
format
(
"{:*^6}"
,
'x'
);
// s4 == "**x***"
// Error: '=' with charT and no integer presentation type
EXPECT_THROW
(
string
s5
=
format
(
"{:=6}"
,
'x'
),
std
::
format_error
);
string
s6
=
format
(
"{:6d}"
,
c
);
// s6 == " 120"
string
s7
=
format
(
"{:=+06d}"
,
c
);
// s7 == "+00120"
string
s8
=
format
(
"{:0=#6x}"
,
0xa
);
// s8 == "0x000a"
string
s9
=
format
(
"{:6}"
,
true
);
// s9 == "true "
EXPECT_EQ
(
s0
,
" 42"
);
EXPECT_EQ
(
s1
,
"x "
);
EXPECT_EQ
(
s2
,
"x*****"
);
EXPECT_EQ
(
s3
,
"*****x"
);
EXPECT_EQ
(
s4
,
"**x***"
);
EXPECT_EQ
(
s6
,
" 120"
);
EXPECT_EQ
(
s7
,
"+00120"
);
EXPECT_EQ
(
s8
,
"0x000a"
);
EXPECT_EQ
(
s9
,
"true "
);
}
TEST
(
StdFormatTest
,
Float
)
{
using
namespace
std
;
double
inf
=
numeric_limits
<
double
>::
infinity
();
double
nan
=
numeric_limits
<
double
>::
quiet_NaN
();
string
s0
=
format
(
"{0:} {0:+} {0:-} {0: }"
,
1
);
// s0 == "1 +1 1 1"
string
s1
=
format
(
"{0:} {0:+} {0:-} {0: }"
,
-
1
);
// s1 == "-1 -1 -1 -1"
string
s2
=
format
(
"{0:} {0:+} {0:-} {0: }"
,
inf
);
// s2 == "inf +inf inf inf"
string
s3
=
format
(
"{0:} {0:+} {0:-} {0: }"
,
nan
);
// s3 == "nan +nan nan nan"
EXPECT_EQ
(
s0
,
"1 +1 1 1"
);
EXPECT_EQ
(
s1
,
"-1 -1 -1 -1"
);
EXPECT_EQ
(
s2
,
"inf +inf inf inf"
);
EXPECT_EQ
(
s3
,
"nan +nan nan nan"
);
}
TEST
(
StdFormatTest
,
Int
)
{
using
namespace
std
;
string
s0
=
format
(
"{}"
,
42
);
// s0 == "42"
string
s1
=
format
(
"{0:b} {0:d} {0:o} {0:x}"
,
42
);
// s1 == "101010 42 52 2a"
string
s2
=
format
(
"{0:#x} {0:#X}"
,
42
);
// s2 == "0x2a 0X2A"
string
s3
=
format
(
"{:n}"
,
1234
);
// s3 == "1,234" (depends on the locale)
EXPECT_EQ
(
s0
,
"42"
);
EXPECT_EQ
(
s1
,
"101010 42 52 2a"
);
EXPECT_EQ
(
s2
,
"0x2a 0X2A"
);
EXPECT_EQ
(
s3
,
"1,234"
);
}
#include <format>
enum
color
{
red
,
green
,
blue
};
const
char
*
color_names
[]
=
{
"red"
,
"green"
,
"blue"
};
template
<
>
struct
std
::
formatter
<
color
>
:
std
::
formatter
<
const
char
*>
{
auto
format
(
color
c
,
format_context
&
ctx
)
{
return
formatter
<
const
char
*>::
format
(
color_names
[
c
],
ctx
);
}
};
struct
err
{};
TEST
(
StdFormatTest
,
Formatter
)
{
std
::
string
s0
=
std
::
format
(
"{}"
,
42
);
// OK: library-provided formatter
//std::string s1 = std::format("{}", L"foo"); // Ill-formed: disabled formatter
std
::
string
s2
=
std
::
format
(
"{}"
,
red
);
// OK: user-provided formatter
//std::string s3 = std::format("{}", err{}); // Ill-formed: disabled formatter
EXPECT_EQ
(
s0
,
"42"
);
EXPECT_EQ
(
s2
,
"red"
);
}
struct
S
{
int
value
;
};
template
<
>
struct
std
::
formatter
<
S
>
{
size_t
width_arg_id
=
0
;
// Parses a width argument id in the format { <digit> }.
constexpr
auto
parse
(
format_parse_context
&
ctx
)
{
auto
iter
=
ctx
.
begin
();
auto
get_char
=
[
&
]()
{
return
iter
!=
ctx
.
end
()
?
*
iter
:
0
;
};
if
(
get_char
()
!=
'{'
)
return
iter
;
++
iter
;
char
c
=
get_char
();
if
(
!
isdigit
(
c
)
||
(
++
iter
,
get_char
())
!=
'}'
)
throw
format_error
(
"invalid format"
);
width_arg_id
=
c
-
'0'
;
ctx
.
check_arg_id
(
width_arg_id
);
return
++
iter
;
}
// Formats S with width given by the argument width_arg_id.
auto
format
(
S
s
,
format_context
&
ctx
)
{
int
width
=
visit_format_arg
([](
auto
value
)
->
int
{
if
constexpr
(
!
is_integral_v
<
decltype
(
value
)
>
)
throw
format_error
(
"width is not integral"
);
else
if
(
value
<
0
||
value
>
numeric_limits
<
int
>::
max
())
throw
format_error
(
"invalid width"
);
else
return
value
;
},
ctx
.
arg
(
width_arg_id
));
return
format_to
(
ctx
.
out
(),
"{0:{1}}"
,
s
.
value
,
width
);
}
};
TEST
(
StdFormatTest
,
Parsing
)
{
std
::
string
s
=
std
::
format
(
"{0:{1}}"
,
S
{
42
},
10
);
// s == " 42"
EXPECT_EQ
(
s
,
" 42"
);
}
#if FMT_USE_INT128
template
<
>
struct
std
::
formatter
<
__int128_t
>
:
std
::
formatter
<
long
long
>
{
auto
format
(
__int128_t
n
,
format_context
&
ctx
)
{
// Format as a long long since we only want to check if it is possible to
// specialize formatter for __int128_t.
return
formatter
<
long
long
>::
format
(
n
,
ctx
);
}
};
TEST
(
StdFormatTest
,
Int128
)
{
__int128_t
n
=
42
;
auto
s
=
std
::
format
(
"{}"
,
n
);
EXPECT_EQ
(
s
,
"42"
);
}
#endif // FMT_USE_INT128
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment