diff --git a/cppformat/posix.h b/cppformat/posix.h index 3f02f388..ae8b4724 100644 --- a/cppformat/posix.h +++ b/cppformat/posix.h @@ -335,7 +335,10 @@ class File { long getpagesize(); #if defined(LC_NUMERIC_MASK) || defined(_MSC_VER) +# define FMT_LOCALE +#endif +#ifdef FMT_LOCALE // A "C" numeric locale. class Locale { private: @@ -362,13 +365,15 @@ class Locale { FMT_DISALLOW_COPY_AND_ASSIGN(Locale); public: + typedef locale_t Type; + Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) { if (!locale_) throw fmt::SystemError(errno, "cannot create locale"); } ~Locale() { freelocale(locale_); } - locale_t get() const { return locale_; } + Type get() const { return locale_; } // Converts string to floating-point number and advances str past the end // of the parsed input. @@ -379,8 +384,7 @@ class Locale { return result; } }; - -#endif // LC_NUMERIC +#endif // FMT_LOCALE } // namespace fmt #if !FMT_USE_RVALUE_REFERENCES diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index e1854c03..13ed1220 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -41,6 +41,7 @@ # undef ERROR #endif +#include "gmock/gmock.h" #include "gtest-extra.h" #include "util.h" @@ -49,6 +50,9 @@ using fmt::ErrorCode; using fmt::File; using testing::internal::scoped_ptr; +using testing::_; +using testing::StrEq; +using testing::Return; namespace { int open_count; @@ -449,3 +453,108 @@ TEST(BufferedFileTest, FilenoNoRetry) { EXPECT_EQ(2, fileno_count); fileno_count = 0; } + +template +struct ScopedMock : testing::StrictMock { + private: + Mock *&global_mock_; + + public: + explicit ScopedMock(Mock *&global_mock) : global_mock_(global_mock) { + global_mock = this; + } + ~ScopedMock() { global_mock_ = 0; } +}; + +struct TestMock {}; + +TEST(ScopedMock, Scope) { + TestMock *global_mock = 0; + { + ScopedMock mock(global_mock); + EXPECT_EQ(&mock, global_mock); + TestMock © = mock; + } + EXPECT_EQ(0, global_mock); +} + +#ifdef FMT_LOCALE + +typedef fmt::Locale::Type LocaleType; + +struct LocaleMock { + MOCK_METHOD3(newlocale, LocaleType (int category_mask, const char *locale, + LocaleType base)); + MOCK_METHOD1(freelocale, void (LocaleType locale)); + + MOCK_METHOD3(strtod_l, double (const char *nptr, char **endptr, + LocaleType locale)); +} *locale_mock; + +#ifdef _MSC_VER +_locale_t _create_locale(int category, const char *locale) { + return locale_mock->newlocale(category, locale, 0); +} + +void _free_locale(_locale_t locale) { + locale_mock->freelocale(locale); +} + +double _strtod_l(const char *nptr, char **endptr, _locale_t locale) { + return locale_mock->strtod_l(nptr, endptr, locale); +} +#endif + +LocaleType newlocale(int category_mask, const char *locale, LocaleType base) { + return locale_mock->newlocale(category_mask, locale, base); +} + +#ifdef __APPLE__ +typedef int FreeLocaleResult; +#else +typedef void FreeLocaleResult; +#endif + +FreeLocaleResult freelocale(LocaleType locale) { + locale_mock->freelocale(locale); +} + +double strtod_l(const char *nptr, char **endptr, LocaleType locale) { + return locale_mock->strtod_l(nptr, endptr, locale); +} + +TEST(LocaleTest, LocaleMock) { + ScopedMock mock(locale_mock); + LocaleType locale = reinterpret_cast(11); + EXPECT_CALL(mock, newlocale(222, StrEq("foo"), locale)); + newlocale(222, "foo", locale); +} + +TEST(LocaleTest, Locale) { +#ifndef LC_NUMERIC_MASK + enum { LC_NUMERIC_MASK = LC_NUMERIC }; +#endif + ScopedMock mock(locale_mock); + LocaleType impl = reinterpret_cast(42); + EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), 0)) + .WillOnce(Return(impl)); + EXPECT_CALL(mock, freelocale(impl)); + fmt::Locale locale; + EXPECT_EQ(impl, locale.get()); +} + +TEST(LocaleTest, Strtod) { + ScopedMock mock(locale_mock); + EXPECT_CALL(mock, newlocale(_, _, _)) + .WillOnce(Return(reinterpret_cast(42))); + EXPECT_CALL(mock, freelocale(_)); + fmt::Locale locale; + const char *str = "4.2"; + char end = 'x'; + EXPECT_CALL(mock, strtod_l(str, _, locale.get())) + .WillOnce(testing::DoAll(testing::SetArgPointee<1>(&end), Return(777))); + EXPECT_EQ(777, locale.strtod(str)); + EXPECT_EQ(&end, str); +} + +#endif // FMT_LOCALE diff --git a/test/posix-test.cc b/test/posix-test.cc index 03ac43d8..f6e3b99d 100644 --- a/test/posix-test.cc +++ b/test/posix-test.cc @@ -388,7 +388,7 @@ TEST(FileTest, FdopenError) { f.fdopen("r"), EBADF, "cannot associate stream with file descriptor"); } -#ifdef LC_NUMERIC_MASK +#ifdef FMT_LOCALE TEST(LocaleTest, Strtod) { fmt::Locale locale; const char *start = "4.2", *ptr = start;