Fix copyright lines
[folly.git] / folly / container / test / EnumerateTest.cpp
1 /*
2  * Copyright 2016-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <array>
18 #include <string>
19 #include <vector>
20
21 #include <folly/Range.h>
22 #include <folly/container/Enumerate.h>
23 #include <folly/portability/GTest.h>
24
25 namespace {
26
27 template <class T>
28 struct IsConstReference {
29   constexpr static bool value = false;
30 };
31 template <class T>
32 struct IsConstReference<const T&> {
33   constexpr static bool value = true;
34 };
35
36 } // namespace
37
38 #define ENUMERATE_TEST_BASIC(DECL, NAME)             \
39   TEST(Enumerate, NAME) {                            \
40     std::vector<std::string> v = {"abc", "a", "ab"}; \
41     size_t i = 0;                                    \
42     for (DECL it : folly::enumerate(v)) {            \
43       EXPECT_EQ(it.index, i);                        \
44       EXPECT_EQ(*it, v[i]);                          \
45       EXPECT_EQ(it->size(), v[i].size());            \
46                                                      \
47       /* Test mutability. */                         \
48       std::string newValue = "x";                    \
49       *it = newValue;                                \
50       EXPECT_EQ(newValue, v[i]);                     \
51                                                      \
52       ++i;                                           \
53     }                                                \
54                                                      \
55     EXPECT_EQ(i, v.size());                          \
56   }
57
58 ENUMERATE_TEST_BASIC(auto, Basic)
59 ENUMERATE_TEST_BASIC(auto&&, BasicRRef)
60
61 #undef ENUMERATE_TEST_BASIC
62
63 #define ENUMERATE_TEST_BASIC_CONST(DECL, NAME)                          \
64   TEST(Enumerate, NAME) {                                               \
65     std::vector<std::string> v = {"abc", "a", "ab"};                    \
66     size_t i = 0;                                                       \
67     for (DECL it : folly::enumerate(v)) {                               \
68       static_assert(                                                    \
69           IsConstReference<decltype(*it)>::value, "Const enumeration"); \
70       EXPECT_EQ(it.index, i);                                           \
71       EXPECT_EQ(*it, v[i]);                                             \
72       EXPECT_EQ(it->size(), v[i].size());                               \
73       ++i;                                                              \
74     }                                                                   \
75                                                                         \
76     EXPECT_EQ(i, v.size());                                             \
77   }
78
79 ENUMERATE_TEST_BASIC_CONST(const auto, BasicConst)
80 ENUMERATE_TEST_BASIC_CONST(const auto&, BasicConstRef)
81 ENUMERATE_TEST_BASIC_CONST(const auto&&, BasicConstRRef)
82
83 #undef ENUMERATE_TEST_BASIC_CONST
84
85 TEST(Enumerate, Temporary) {
86   std::vector<std::string> v = {"abc", "a", "ab"};
87   size_t i = 0;
88   for (auto&& it : folly::enumerate(decltype(v)(v))) { // Copy v.
89     EXPECT_EQ(it.index, i);
90     EXPECT_EQ(*it, v[i]);
91     EXPECT_EQ(it->size(), v[i].size());
92     ++i;
93   }
94
95   EXPECT_EQ(i, v.size());
96 };
97
98 TEST(Enumerate, BasicConstArg) {
99   const std::vector<std::string> v = {"abc", "a", "ab"};
100   size_t i = 0;
101   for (auto&& it : folly::enumerate(v)) {
102     static_assert(
103         IsConstReference<decltype(*it)>::value, "Enumerating a const vector");
104     EXPECT_EQ(it.index, i);
105     EXPECT_EQ(*it, v[i]);
106     EXPECT_EQ(it->size(), v[i].size());
107     ++i;
108   }
109
110   EXPECT_EQ(i, v.size());
111 }
112
113 TEST(Enumerate, TemporaryConstEnumerate) {
114   std::vector<std::string> v = {"abc", "a", "ab"};
115   size_t i = 0;
116   for (const auto&& it : folly::enumerate(decltype(v)(v))) { // Copy v.
117     static_assert(IsConstReference<decltype(*it)>::value, "Const enumeration");
118     EXPECT_EQ(it.index, i);
119     EXPECT_EQ(*it, v[i]);
120     EXPECT_EQ(it->size(), v[i].size());
121     ++i;
122   }
123
124   EXPECT_EQ(i, v.size());
125 }
126
127 TEST(Enumerate, RangeSupport) {
128   std::vector<std::string> v = {"abc", "a", "ab"};
129   size_t i = 0;
130   for (const auto&& it : folly::enumerate(folly::range(v))) {
131     EXPECT_EQ(it.index, i);
132     EXPECT_EQ(*it, v[i]);
133     EXPECT_EQ(it->size(), v[i].size());
134     ++i;
135   }
136
137   EXPECT_EQ(i, v.size());
138 }
139
140 TEST(Enumerate, EmptyRange) {
141   std::vector<std::string> v;
142   for (auto&& it : folly::enumerate(v)) {
143     (void)it; // Silence warnings.
144     ADD_FAILURE();
145   }
146 }
147
148 class CStringRange {
149   const char* cstr;
150
151  public:
152   struct Sentinel {};
153
154   explicit CStringRange(const char* cstr) : cstr(cstr) {}
155
156   const char* begin() const {
157     return cstr;
158   }
159   Sentinel end() const {
160     return Sentinel{};
161   }
162 };
163
164 bool operator==(const char* c, CStringRange::Sentinel) {
165   return *c == 0;
166 }
167
168 TEST(Enumerate, Cpp17Support) {
169   std::array<char, 5> test = {"test"};
170   // Can't use range based for loop until C++17, so test manually
171   // Equivalent to:
172   // for (const auto&& it : folly::enumerate(CStringRange{test.data()})) { ... }
173   {
174     auto&& enumerate = folly::enumerate(CStringRange{test.data()});
175     auto begin = enumerate.begin();
176     auto end = enumerate.end();
177     for (; begin != end; ++begin) {
178       const auto&& it = *begin;
179
180       ASSERT_LT(it.index, test.size());
181       EXPECT_EQ(*it, test[it.index]);
182     }
183   }
184 }