ranges-test.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Formatting library for C++ - the core API
  2. //
  3. // Copyright (c) 2012 - present, Victor Zverovich
  4. // All rights reserved.
  5. //
  6. // For the license information refer to format.h.
  7. //
  8. // Copyright (c) 2018 - present, Remotion (Igor Schulz)
  9. // All Rights Reserved
  10. // {fmt} support for ranges, containers and types tuple interface.
  11. #include "fmt/ranges.h"
  12. #include <gtest/gtest.h>
  13. // Check if 'if constexpr' is supported.
  14. #if (__cplusplus > 201402L) || \
  15. (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
  16. # include <array>
  17. # include <map>
  18. # include <string>
  19. # include <vector>
  20. TEST(RangesTest, FormatVector) {
  21. std::vector<int32_t> iv{1, 2, 3, 5, 7, 11};
  22. auto ivf = fmt::format("{}", iv);
  23. EXPECT_EQ("{1, 2, 3, 5, 7, 11}", ivf);
  24. }
  25. TEST(RangesTest, FormatVector2) {
  26. std::vector<std::vector<int32_t>> ivv{{1, 2}, {3, 5}, {7, 11}};
  27. auto ivf = fmt::format("{}", ivv);
  28. EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", ivf);
  29. }
  30. TEST(RangesTest, FormatMap) {
  31. std::map<std::string, int32_t> simap{{"one", 1}, {"two", 2}};
  32. EXPECT_EQ("{(\"one\", 1), (\"two\", 2)}", fmt::format("{}", simap));
  33. }
  34. TEST(RangesTest, FormatPair) {
  35. std::pair<int64_t, float> pa1{42, 1.5f};
  36. EXPECT_EQ("(42, 1.5)", fmt::format("{}", pa1));
  37. }
  38. TEST(RangesTest, FormatTuple) {
  39. std::tuple<int64_t, float, std::string, char> t{42, 1.5f, "this is tuple",
  40. 'i'};
  41. EXPECT_EQ("(42, 1.5, \"this is tuple\", 'i')", fmt::format("{}", t));
  42. EXPECT_EQ("()", fmt::format("{}", std::tuple<>()));
  43. }
  44. TEST(RangesTest, JoinTuple) {
  45. // Value tuple args
  46. std::tuple<char, int, float> t1 = std::make_tuple('a', 1, 2.0f);
  47. EXPECT_EQ("(a, 1, 2)", fmt::format("({})", fmt::join(t1, ", ")));
  48. // Testing lvalue tuple args
  49. int x = 4;
  50. std::tuple<char, int&> t2{'b', x};
  51. EXPECT_EQ("b + 4", fmt::format("{}", fmt::join(t2, " + ")));
  52. // Empty tuple
  53. std::tuple<> t3;
  54. EXPECT_EQ("", fmt::format("{}", fmt::join(t3, "|")));
  55. // Single element tuple
  56. std::tuple<float> t4{4.0f};
  57. EXPECT_EQ("4", fmt::format("{}", fmt::join(t4, "/")));
  58. }
  59. TEST(RangesTest, JoinInitializerList) {
  60. EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join({1, 2, 3}, ", ")));
  61. EXPECT_EQ("fmt rocks !",
  62. fmt::format("{}", fmt::join({"fmt", "rocks", "!"}, " ")));
  63. }
  64. struct my_struct {
  65. int32_t i;
  66. std::string str; // can throw
  67. template <size_t N> decltype(auto) get() const noexcept {
  68. if constexpr (N == 0)
  69. return i;
  70. else if constexpr (N == 1)
  71. return fmt::string_view{str};
  72. }
  73. };
  74. template <size_t N> decltype(auto) get(const my_struct& s) noexcept {
  75. return s.get<N>();
  76. }
  77. namespace std {
  78. template <> struct tuple_size<my_struct> : std::integral_constant<size_t, 2> {};
  79. template <size_t N> struct tuple_element<N, my_struct> {
  80. using type = decltype(std::declval<my_struct>().get<N>());
  81. };
  82. } // namespace std
  83. TEST(RangesTest, FormatStruct) {
  84. my_struct mst{13, "my struct"};
  85. EXPECT_EQ("(13, \"my struct\")", fmt::format("{}", mst));
  86. }
  87. TEST(RangesTest, FormatTo) {
  88. char buf[10];
  89. auto end = fmt::format_to(buf, "{}", std::vector{1, 2, 3});
  90. *end = '\0';
  91. EXPECT_STREQ(buf, "{1, 2, 3}");
  92. }
  93. struct path_like {
  94. const path_like* begin() const;
  95. const path_like* end() const;
  96. operator std::string() const;
  97. };
  98. TEST(RangesTest, PathLike) {
  99. EXPECT_FALSE((fmt::is_range<path_like, char>::value));
  100. }
  101. #endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >
  102. // 201402L && _MSC_VER >= 1910)
  103. #ifdef FMT_USE_STRING_VIEW
  104. struct string_like {
  105. const char* begin();
  106. const char* end();
  107. explicit operator fmt::string_view() const { return "foo"; }
  108. explicit operator std::string_view() const { return "foo"; }
  109. };
  110. TEST(RangesTest, FormatStringLike) {
  111. EXPECT_EQ("foo", fmt::format("{}", string_like()));
  112. }
  113. #endif // FMT_USE_STRING_VIEW
  114. struct zstring_sentinel {};
  115. bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; }
  116. bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; }
  117. struct zstring {
  118. const char* p;
  119. const char* begin() const { return p; }
  120. zstring_sentinel end() const { return {}; }
  121. };
  122. TEST(RangesTest, JoinSentinel) {
  123. zstring hello{"hello"};
  124. EXPECT_EQ("{'h', 'e', 'l', 'l', 'o'}", fmt::format("{}", hello));
  125. EXPECT_EQ("h_e_l_l_o", fmt::format("{}", fmt::join(hello, "_")));
  126. }
  127. // A range that provides non-const only begin()/end() to test fmt::join handles
  128. // that
  129. //
  130. // Some ranges (eg those produced by range-v3's views::filter()) can cache
  131. // information during iteration so they only provide non-const begin()/end().
  132. template <typename T> class non_const_only_range {
  133. private:
  134. std::vector<T> vec;
  135. public:
  136. using const_iterator = typename ::std::vector<T>::const_iterator;
  137. template <typename... Args>
  138. explicit non_const_only_range(Args&&... args)
  139. : vec(::std::forward<Args>(args)...) {}
  140. const_iterator begin() { return vec.begin(); }
  141. const_iterator end() { return vec.end(); }
  142. };
  143. TEST(RangesTest, JoinRange) {
  144. non_const_only_range<int> x(3u, 0);
  145. EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(x, ",")));
  146. EXPECT_EQ(
  147. "0,0,0",
  148. fmt::format("{}", fmt::join(non_const_only_range<int>(3u, 0), ",")));
  149. std::vector<int> y(3u, 0);
  150. EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(y, ",")));
  151. EXPECT_EQ("0,0,0",
  152. fmt::format("{}", fmt::join(std::vector<int>(3u, 0), ",")));
  153. const std::vector<int> z(3u, 0);
  154. EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ",")));
  155. }
  156. #if !FMT_MSC_VER || FMT_MSC_VER >= 1927
  157. struct unformattable {};
  158. TEST(RangesTest, UnformattableRange) {
  159. EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>,
  160. fmt::format_context>::value));
  161. }
  162. #endif