#include <catch2/catch_tostring.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/internal/catch_context.hpp>
#include <catch2/internal/catch_polyfills.hpp>
#include <cmath>
#include <iomanip>
namespace
Catch {
namespace
Detail {
namespace
{
const
int
hexThreshold = 255;
struct
Endianness {
enum
Arch { Big, Little };
static
Arch which() {
int
one = 1;
auto
value = *
reinterpret_cast
<
char
*>(&one);
return
value ? Little : Big;
}
};
template
<
typename
T>
std::string fpToString(T value,
int
precision) {
if
(Catch::isnan(value)) {
return
"nan"
;
}
ReusableStringStream rss;
rss << std::setprecision(precision)
<< std::fixed
<< value;
std::string d = rss.str();
std::
size_t
i = d.find_last_not_of(
'0'
);
if
(i != std::string::npos && i != d.size() - 1) {
if
(d[i] ==
'.'
)
i++;
d = d.substr(0, i + 1);
}
return
d;
}
}
std::string convertIntoString(StringRef string,
bool
escapeInvisibles) {
std::string ret;
ret.reserve(string.size() + 2);
if
(!escapeInvisibles) {
ret +=
'"'
;
ret += string;
ret +=
'"'
;
return
ret;
}
ret +=
'"'
;
for
(
char
c : string) {
switch
(c) {
case
'\r'
:
ret.append(
"\\r"
);
break
;
case
'\n'
:
ret.append(
"\\n"
);
break
;
case
'\t'
:
ret.append(
"\\t"
);
break
;
case
'\f'
:
ret.append(
"\\f"
);
break
;
default
:
ret.push_back(c);
break
;
}
}
ret +=
'"'
;
return
ret;
}
std::string convertIntoString(StringRef string) {
return
convertIntoString(string, getCurrentContext().getConfig()->showInvisibles());
}
std::string rawMemoryToString(
const
void
*object, std::
size_t
size ) {
int
i = 0, end =
static_cast
<
int
>( size ), inc = 1;
if
( Endianness::which() == Endianness::Little ) {
i = end-1;
end = inc = -1;
}
unsigned
char
const
*bytes =
static_cast
<unsigned
char
const
*>(object);
ReusableStringStream rss;
rss <<
"0x"
<< std::setfill(
'0'
) << std::hex;
for
( ; i != end; i += inc )
rss << std::setw(2) <<
static_cast
<unsigned>(bytes[i]);
return
rss.str();
}
}
std::string StringMaker<std::string>::convert(
const
std::string& str) {
return
Detail::convertIntoString( str );
}
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
std::string StringMaker<std::string_view>::convert(std::string_view str) {
return
Detail::convertIntoString( StringRef( str.data(), str.size() ) );
}
#endif
std::string StringMaker<
char
const
*>::convert(
char
const
* str) {
if
(str) {
return
Detail::convertIntoString( str );
}
else
{
return
{
"{null string}"
};
}
}
std::string StringMaker<
char
*>::convert(
char
* str) {
if
(str) {
return
Detail::convertIntoString( str );
}
else
{
return
{
"{null string}"
};
}
}
#ifdef CATCH_CONFIG_WCHAR
std::string StringMaker<std::wstring>::convert(
const
std::wstring& wstr) {
std::string s;
s.reserve(wstr.size());
for
(
auto
c : wstr) {
s += (c <= 0xff) ?
static_cast
<
char
>(c) :
'?'
;
}
return
::Catch::Detail::stringify(s);
}
# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
return
StringMaker<std::wstring>::convert(std::wstring(str));
}
# endif
std::string StringMaker<
wchar_t
const
*>::convert(
wchar_t
const
* str) {
if
(str) {
return
::Catch::Detail::stringify(std::wstring{ str });
}
else
{
return
{
"{null string}"
};
}
}
std::string StringMaker<
wchar_t
*>::convert(
wchar_t
* str) {
if
(str) {
return
::Catch::Detail::stringify(std::wstring{ str });
}
else
{
return
{
"{null string}"
};
}
}
#endif
#if defined(CATCH_CONFIG_CPP17_BYTE)
#include <cstddef>
std::string StringMaker<std::byte>::convert(std::byte value) {
return
::Catch::Detail::stringify(std::to_integer<unsigned
long
long
>(value));
}
#endif // defined(CATCH_CONFIG_CPP17_BYTE)
std::string StringMaker<
int
>::convert(
int
value) {
return
::Catch::Detail::stringify(
static_cast
<
long
long
>(value));
}
std::string StringMaker<
long
>::convert(
long
value) {
return
::Catch::Detail::stringify(
static_cast
<
long
long
>(value));
}
std::string StringMaker<
long
long
>::convert(
long
long
value) {
ReusableStringStream rss;
rss << value;
if
(value > Detail::hexThreshold) {
rss <<
" (0x"
<< std::hex << value <<
')'
;
}
return
rss.str();
}
std::string StringMaker<unsigned
int
>::convert(unsigned
int
value) {
return
::Catch::Detail::stringify(
static_cast
<unsigned
long
long
>(value));
}
std::string StringMaker<unsigned
long
>::convert(unsigned
long
value) {
return
::Catch::Detail::stringify(
static_cast
<unsigned
long
long
>(value));
}
std::string StringMaker<unsigned
long
long
>::convert(unsigned
long
long
value) {
ReusableStringStream rss;
rss << value;
if
(value > Detail::hexThreshold) {
rss <<
" (0x"
<< std::hex << value <<
')'
;
}
return
rss.str();
}
std::string StringMaker<
signed
char
>::convert(
signed
char
value) {
if
(value ==
'\r'
) {
return
"'\\r'"
;
}
else
if
(value ==
'\f'
) {
return
"'\\f'"
;
}
else
if
(value ==
'\n'
) {
return
"'\\n'"
;
}
else
if
(value ==
'\t'
) {
return
"'\\t'"
;
}
else
if
(
'\0'
<= value && value <
' '
) {
return
::Catch::Detail::stringify(
static_cast
<unsigned
int
>(value));
}
else
{
char
chstr[] =
"' '"
;
chstr[1] = value;
return
chstr;
}
}
std::string StringMaker<
char
>::convert(
char
c) {
return
::Catch::Detail::stringify(
static_cast
<
signed
char
>(c));
}
std::string StringMaker<unsigned
char
>::convert(unsigned
char
value) {
return
::Catch::Detail::stringify(
static_cast
<
char
>(value));
}
int
StringMaker<
float
>::precision = std::numeric_limits<
float
>::max_digits10;
std::string StringMaker<
float
>::convert(
float
value) {
return
Detail::fpToString(value, precision) +
'f'
;
}
int
StringMaker<
double
>::precision = std::numeric_limits<
double
>::max_digits10;
std::string StringMaker<
double
>::convert(
double
value) {
return
Detail::fpToString(value, precision);
}
}