Fix tests on MSVC, take 2.

This commit is contained in:
Victor Zverovich 2014-07-31 07:43:14 -07:00
parent 3f444fe3e2
commit d81fafc295
3 changed files with 58 additions and 18 deletions

View File

@ -207,16 +207,6 @@ class PrecisionHandler :
} }
}; };
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
template <typename T>
struct MakeUnsigned { typedef T Type; };
template <>
struct MakeUnsigned<signed char> { typedef unsigned char Type; };
template <>
struct MakeUnsigned<short> { typedef unsigned short Type; };
// Converts an integer argument to type T. // Converts an integer argument to type T.
template <typename T> template <typename T>
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> { class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
@ -229,12 +219,26 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
template <typename U> template <typename U>
void visit_any_int(U value) { void visit_any_int(U value) {
if (type_ == 'd' || type_ == 'i') { bool is_signed = type_ == 'd' || type_ == 'i';
arg_.type = fmt::internal::Arg::INT; using fmt::internal::Arg;
arg_.int_value = static_cast<T>(value); if (sizeof(T) <= sizeof(int)) {
if (is_signed) {
arg_.type = Arg::INT;
arg_.int_value = static_cast<T>(value);
} else {
arg_.type = Arg::UINT;
arg_.uint_value =
static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value);
}
} else { } else {
arg_.type = fmt::internal::Arg::UINT; if (is_signed) {
arg_.uint_value = static_cast<typename MakeUnsigned<T>::Type>(value); arg_.type = Arg::LONG_LONG;
arg_.long_long_value = static_cast<T>(value);
} else {
arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value =
static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value);
}
} }
} }
}; };
@ -902,6 +906,10 @@ void fmt::internal::PrintfFormatter<Char>::format(
} }
// Parse length and convert the argument to the required type. // Parse length and convert the argument to the required type.
// Conversion is done for compatibility with glibc's printf, MSVC's
// printf simply ignores width specifiers. For example:
// printf("%hhd", -129);
// prints 127 when using glibc's printf and -129 when using MSVC's one.
switch (*s) { switch (*s) {
case 'h': { case 'h': {
++s; ++s;
@ -912,6 +920,9 @@ void fmt::internal::PrintfFormatter<Char>::format(
break; break;
} }
case 'l': case 'l':
++s;
ArgConverter<long>(arg, *s).visit(arg);
break;
case 'j': case 'j':
case 'z': case 'z':
case 't': case 't':

View File

@ -420,6 +420,18 @@ struct IntTraits {
TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType; TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
}; };
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
template <typename T>
struct MakeUnsigned { typedef T Type; };
#define SPECIALIZE_MAKE_UNSIGNED(T) \
template <> \
struct MakeUnsigned<signed T> { typedef unsigned T Type; }
SPECIALIZE_MAKE_UNSIGNED(char);
SPECIALIZE_MAKE_UNSIGNED(short);
SPECIALIZE_MAKE_UNSIGNED(long);
template <typename T> template <typename T>
struct IsLongDouble { enum {VALUE = 0}; }; struct IsLongDouble { enum {VALUE = 0}; };

View File

@ -273,10 +273,27 @@ TEST(PrintfTest, DynamicPrecision) {
} }
} }
#define EXPECT_STD_PRINTF(format, Type, arg) { \ // Cast value to T to workaround an issue with MSVC not implementing
// various format specifiers.
template <typename T, typename U>
T Cast(U value) { return value; }
bool IsSupported(const std::string &format) {
#ifdef _MSVC
// MSVC doesn't support hh, j, z and t format specifiers.
return format != "hh";
#else
return true;
#endif
}
#define EXPECT_STD_PRINTF(format, T, arg) { \
char buffer[BUFFER_SIZE]; \ char buffer[BUFFER_SIZE]; \
Type conv_arg = static_cast<Type>(arg); \ if (IsSupported(format)) \
safe_sprintf(buffer, fmt::StringRef(format).c_str(), conv_arg); \ safe_sprintf(buffer, fmt::StringRef(format).c_str(), arg); \
else \
safe_sprintf(buffer, fmt::StringRef(format).c_str(), \
Cast<typename fmt::internal::MakeUnsigned<T>::Type>(arg)); \
EXPECT_PRINTF(buffer, format, arg); \ EXPECT_PRINTF(buffer, format, arg); \
} }