• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 //
15 // These tests were forked from
16 // https://cs.opensource.google/abseil/abseil-cpp/+/main:absl/algorithm/algorithm_test.cc;drc=38b704384cd2f17590b3922b97744be0b43622c9
17 // However they were modified to work with containers available in Pigweed
18 // without dynamic allocations, i.e. no std::vector, std::map, std::list, etc.
19 #include "pw_containers/algorithm.h"
20 
21 #include <algorithm>
22 #include <iterator>
23 
24 #include "pw_containers/flat_map.h"
25 #include "pw_containers/intrusive_list.h"
26 #include "pw_containers/vector.h"
27 #include "pw_span/span.h"
28 #include "pw_unit_test/framework.h"
29 
30 namespace {
31 
32 class TestItem : public pw::IntrusiveList<TestItem>::Item {
33  public:
TestItem()34   TestItem() : number_(0) {}
TestItem(int number)35   TestItem(int number) : number_(number) {}
36 
37   // Add equality comparison to ensure comparisons are done by identity rather
38   // than equality for the remove function.
operator ==(const TestItem & other) const39   bool operator==(const TestItem& other) const {
40     return number_ == other.number_;
41   }
42 
43  private:
44   int number_;
45 };
46 
47 // Most of these tests just check that the code compiles, not that it
48 // does the right thing. That's fine since the functions just forward
49 // to the STL implementation.
50 class NonMutatingTest : public testing::Test {
51  protected:
52   std::array<int, 3> span_array_ = {1, 2, 3};
53   pw::span<int> span_{NonMutatingTest::span_array_};
54   pw::Vector<int, 3> vector_ = {1, 2, 3};
55   int array_[3] = {1, 2, 3};
56 };
57 
58 struct AccumulateCalls {
operator ()__anon9019e3fe0111::AccumulateCalls59   void operator()(int value) { calls.push_back(value); }
60   pw::Vector<int, 10> calls;
61 };
62 
Predicate(int value)63 bool Predicate(int value) { return value < 3; }
BinPredicate(int v1,int v2)64 bool BinPredicate(int v1, int v2) { return v1 < v2; }
Equals(int v1,int v2)65 bool Equals(int v1, int v2) { return v1 == v2; }
66 
67 }  // namespace
68 
TEST_F(NonMutatingTest,AllOf)69 TEST_F(NonMutatingTest, AllOf) {
70   const pw::Vector<int>& v = vector_;
71   EXPECT_FALSE(pw::containers::AllOf(v, [](int x) { return x > 1; }));
72   EXPECT_TRUE(pw::containers::AllOf(v, [](int x) { return x > 0; }));
73 }
74 
TEST_F(NonMutatingTest,AnyOf)75 TEST_F(NonMutatingTest, AnyOf) {
76   const pw::Vector<int>& v = vector_;
77   EXPECT_TRUE(pw::containers::AnyOf(v, [](int x) { return x > 2; }));
78   EXPECT_FALSE(pw::containers::AnyOf(v, [](int x) { return x > 5; }));
79 }
80 
TEST_F(NonMutatingTest,NoneOf)81 TEST_F(NonMutatingTest, NoneOf) {
82   const pw::Vector<int>& v = vector_;
83   EXPECT_FALSE(pw::containers::NoneOf(v, [](int x) { return x > 2; }));
84   EXPECT_TRUE(pw::containers::NoneOf(v, [](int x) { return x > 5; }));
85 }
86 
TEST_F(NonMutatingTest,ForEach)87 TEST_F(NonMutatingTest, ForEach) {
88   AccumulateCalls c = pw::containers::ForEach(span_, AccumulateCalls());
89   std::sort(c.calls.begin(), c.calls.end());
90   EXPECT_EQ(vector_, c.calls);
91 }
92 
TEST_F(NonMutatingTest,FindReturnsCorrectType)93 TEST_F(NonMutatingTest, FindReturnsCorrectType) {
94   auto it = pw::containers::Find(span_, 3);
95   EXPECT_EQ(3, *it);
96   pw::containers::Find(vector_, 3);
97 }
98 
TEST_F(NonMutatingTest,FindIf)99 TEST_F(NonMutatingTest, FindIf) { pw::containers::FindIf(span_, Predicate); }
100 
TEST_F(NonMutatingTest,FindIfNot)101 TEST_F(NonMutatingTest, FindIfNot) {
102   pw::containers::FindIfNot(span_, Predicate);
103 }
104 
TEST_F(NonMutatingTest,FindEnd)105 TEST_F(NonMutatingTest, FindEnd) {
106   pw::containers::FindEnd(array_, vector_);
107   pw::containers::FindEnd(vector_, array_);
108 }
109 
TEST_F(NonMutatingTest,FindEndWithPredicate)110 TEST_F(NonMutatingTest, FindEndWithPredicate) {
111   pw::containers::FindEnd(array_, vector_, BinPredicate);
112   pw::containers::FindEnd(vector_, array_, BinPredicate);
113 }
114 
TEST_F(NonMutatingTest,FindFirstOf)115 TEST_F(NonMutatingTest, FindFirstOf) {
116   pw::containers::FindFirstOf(span_, array_);
117   pw::containers::FindFirstOf(array_, span_);
118 }
119 
TEST_F(NonMutatingTest,FindFirstOfWithPredicate)120 TEST_F(NonMutatingTest, FindFirstOfWithPredicate) {
121   pw::containers::FindFirstOf(span_, array_, BinPredicate);
122   pw::containers::FindFirstOf(array_, span_, BinPredicate);
123 }
124 
TEST_F(NonMutatingTest,AdjacentFind)125 TEST_F(NonMutatingTest, AdjacentFind) { pw::containers::AdjacentFind(array_); }
126 
TEST_F(NonMutatingTest,AdjacentFindWithPredicate)127 TEST_F(NonMutatingTest, AdjacentFindWithPredicate) {
128   pw::containers::AdjacentFind(array_, BinPredicate);
129 }
130 
TEST_F(NonMutatingTest,Count)131 TEST_F(NonMutatingTest, Count) {
132   EXPECT_EQ(1, pw::containers::Count(span_, 3));
133 }
134 
TEST_F(NonMutatingTest,CountIf)135 TEST_F(NonMutatingTest, CountIf) {
136   EXPECT_EQ(2, pw::containers::CountIf(span_, Predicate));
137 }
138 
TEST_F(NonMutatingTest,Mismatch)139 TEST_F(NonMutatingTest, Mismatch) {
140   // Testing necessary as pw::containers::Mismatch executes logic.
141   {
142     auto result = pw::containers::Mismatch(span_, vector_);
143     EXPECT_EQ(result.first, span_.end());
144     EXPECT_EQ(result.second, vector_.end());
145   }
146   {
147     auto result = pw::containers::Mismatch(vector_, span_);
148     EXPECT_EQ(result.first, vector_.end());
149     EXPECT_EQ(result.second, span_.end());
150   }
151 
152   vector_.back() = 5;
153   {
154     auto result = pw::containers::Mismatch(span_, vector_);
155     EXPECT_EQ(result.first, std::prev(span_.end()));
156     EXPECT_EQ(result.second, std::prev(vector_.end()));
157   }
158   {
159     auto result = pw::containers::Mismatch(vector_, span_);
160     EXPECT_EQ(result.first, std::prev(vector_.end()));
161     EXPECT_EQ(result.second, std::prev(span_.end()));
162   }
163 
164   vector_.pop_back();
165   {
166     auto result = pw::containers::Mismatch(span_, vector_);
167     EXPECT_EQ(result.first, std::prev(span_.end()));
168     EXPECT_EQ(result.second, vector_.end());
169   }
170   {
171     auto result = pw::containers::Mismatch(vector_, span_);
172     EXPECT_EQ(result.first, vector_.end());
173     EXPECT_EQ(result.second, std::prev(span_.end()));
174   }
175   {
176     struct NoNotEquals {
177       constexpr bool operator==(NoNotEquals) const { return true; }
178       constexpr bool operator!=(NoNotEquals) const = delete;
179     };
180     pw::Vector<NoNotEquals, 1> first;
181     std::array<NoNotEquals, 1> second;
182 
183     // Check this still compiles.
184     pw::containers::Mismatch(first, second);
185   }
186 }
187 
TEST_F(NonMutatingTest,MismatchWithPredicate)188 TEST_F(NonMutatingTest, MismatchWithPredicate) {
189   // Testing necessary as pw::containers::Mismatch executes logic.
190   {
191     auto result = pw::containers::Mismatch(span_, vector_, BinPredicate);
192     EXPECT_EQ(result.first, span_.begin());
193     EXPECT_EQ(result.second, vector_.begin());
194   }
195   {
196     auto result = pw::containers::Mismatch(vector_, span_, BinPredicate);
197     EXPECT_EQ(result.first, vector_.begin());
198     EXPECT_EQ(result.second, span_.begin());
199   }
200 
201   vector_.front() = 0;
202   {
203     auto result = pw::containers::Mismatch(span_, vector_, BinPredicate);
204     EXPECT_EQ(result.first, span_.begin());
205     EXPECT_EQ(result.second, vector_.begin());
206   }
207   {
208     auto result = pw::containers::Mismatch(vector_, span_, BinPredicate);
209     EXPECT_EQ(result.first, std::next(vector_.begin()));
210     EXPECT_EQ(result.second, std::next(span_.begin()));
211   }
212 
213   vector_.clear();
214   {
215     auto result = pw::containers::Mismatch(span_, vector_, BinPredicate);
216     EXPECT_EQ(result.first, span_.begin());
217     EXPECT_EQ(result.second, vector_.end());
218   }
219   {
220     auto result = pw::containers::Mismatch(vector_, span_, BinPredicate);
221     EXPECT_EQ(result.first, vector_.end());
222     EXPECT_EQ(result.second, span_.begin());
223   }
224 }
225 
TEST_F(NonMutatingTest,Equal)226 TEST_F(NonMutatingTest, Equal) {
227   EXPECT_TRUE(pw::containers::Equal(vector_, span_));
228   EXPECT_TRUE(pw::containers::Equal(span_, vector_));
229   EXPECT_TRUE(pw::containers::Equal(span_, array_));
230   EXPECT_TRUE(pw::containers::Equal(array_, vector_));
231 
232   pw::containers::FlatMap<char, int, 3> map1({{{'A', 1}, {'B', 2}, {'C', 3}}});
233   pw::containers::FlatMap<char, int, 3> map2({{{'B', 2}, {'A', 1}, {'C', 3}}});
234   pw::containers::FlatMap<char, int, 3> map3({{{'A', 1}, {'B', 2}, {'C', 4}}});
235   pw::containers::FlatMap<char, int, 3> map4({{{'A', 1}, {'B', 2}, {'D', 3}}});
236 
237   EXPECT_TRUE(pw::containers::Equal(map1, map2));
238   EXPECT_FALSE(pw::containers::Equal(map1, map3));
239   EXPECT_FALSE(pw::containers::Equal(map1, map4));
240 
241   // Test that behavior appropriately differs from that of equal().
242   pw::Vector<int, 4> vector_plus = {1, 2, 3};
243   vector_plus.push_back(4);
244   EXPECT_FALSE(pw::containers::Equal(vector_plus, span_));
245   EXPECT_FALSE(pw::containers::Equal(span_, vector_plus));
246   EXPECT_FALSE(pw::containers::Equal(array_, vector_plus));
247 }
248 
TEST_F(NonMutatingTest,EqualWithPredicate)249 TEST_F(NonMutatingTest, EqualWithPredicate) {
250   EXPECT_TRUE(pw::containers::Equal(vector_, span_, Equals));
251   EXPECT_TRUE(pw::containers::Equal(span_, vector_, Equals));
252   EXPECT_TRUE(pw::containers::Equal(array_, span_, Equals));
253   EXPECT_TRUE(pw::containers::Equal(vector_, array_, Equals));
254 
255   // Test that behavior appropriately differs from that of equal().
256   pw::Vector<int, 4> vector_plus = {1, 2, 3};
257   vector_plus.push_back(4);
258   EXPECT_FALSE(pw::containers::Equal(vector_plus, span_, Equals));
259   EXPECT_FALSE(pw::containers::Equal(span_, vector_plus, Equals));
260   EXPECT_FALSE(pw::containers::Equal(vector_plus, array_, Equals));
261 }
262 
TEST_F(NonMutatingTest,IsPermutation)263 TEST_F(NonMutatingTest, IsPermutation) {
264   auto vector_permut_ = vector_;
265   std::next_permutation(vector_permut_.begin(), vector_permut_.end());
266   EXPECT_TRUE(pw::containers::IsPermutation(vector_permut_, span_));
267   EXPECT_TRUE(pw::containers::IsPermutation(span_, vector_permut_));
268 
269   // Test that behavior appropriately differs from that of is_permutation().
270   pw::Vector<int, 4> vector_plus = {1, 2, 3};
271   vector_plus.push_back(4);
272   EXPECT_FALSE(pw::containers::IsPermutation(vector_plus, span_));
273   EXPECT_FALSE(pw::containers::IsPermutation(span_, vector_plus));
274 }
275 
TEST_F(NonMutatingTest,IsPermutationWithPredicate)276 TEST_F(NonMutatingTest, IsPermutationWithPredicate) {
277   auto vector_permut_ = vector_;
278   std::next_permutation(vector_permut_.begin(), vector_permut_.end());
279   EXPECT_TRUE(pw::containers::IsPermutation(vector_permut_, span_, Equals));
280   EXPECT_TRUE(pw::containers::IsPermutation(span_, vector_permut_, Equals));
281 
282   // Test that behavior appropriately differs from that of is_permutation().
283   pw::Vector<int, 4> vector_plus = {1, 2, 3};
284   vector_plus.push_back(4);
285   EXPECT_FALSE(pw::containers::IsPermutation(vector_plus, span_, Equals));
286   EXPECT_FALSE(pw::containers::IsPermutation(span_, vector_plus, Equals));
287 }
288 
TEST_F(NonMutatingTest,Search)289 TEST_F(NonMutatingTest, Search) {
290   pw::containers::Search(span_, vector_);
291   pw::containers::Search(vector_, span_);
292   pw::containers::Search(array_, span_);
293 }
294 
TEST_F(NonMutatingTest,SearchWithPredicate)295 TEST_F(NonMutatingTest, SearchWithPredicate) {
296   pw::containers::Search(span_, vector_, BinPredicate);
297   pw::containers::Search(vector_, span_, BinPredicate);
298 }
299 
TEST_F(NonMutatingTest,SearchN)300 TEST_F(NonMutatingTest, SearchN) { pw::containers::SearchN(span_, 3, 1); }
301 
TEST_F(NonMutatingTest,SearchNWithPredicate)302 TEST_F(NonMutatingTest, SearchNWithPredicate) {
303   pw::containers::SearchN(span_, 3, 1, BinPredicate);
304 }
305