1 // Copyright 2020 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 #include <array>
16 #include <cstddef>
17 #include <span>
18 #include <string_view>
19 #include <vector>
20 
21 #include "gtest/gtest.h"
22 #include "pw_kvs/internal/span_traits.h"
23 
24 namespace pw::kvs {
25 namespace {
26 
27 using internal::make_span;
28 using std::byte;
29 using std::dynamic_extent;
30 using std::span;
31 
32 // Test that the ConvertsToSpan trait correctly idenitifies types that convert
33 // to std::span.
34 
35 // Basic types should not convert to span.
36 struct Foo {};
37 
38 static_assert(!ConvertsToSpan<Foo>());
39 static_assert(!ConvertsToSpan<int>());
40 static_assert(!ConvertsToSpan<void>());
41 static_assert(!ConvertsToSpan<byte>());
42 static_assert(!ConvertsToSpan<byte*>());
43 
44 // Arrays without an extent are just pointers -- these should not convert.
45 static_assert(!ConvertsToSpan<bool[]>());
46 static_assert(!ConvertsToSpan<const int[]>());
47 static_assert(!ConvertsToSpan<bool (&)[]>());
48 static_assert(!ConvertsToSpan<const int (&)[]>());
49 static_assert(!ConvertsToSpan<bool(&&)[]>());
50 static_assert(!ConvertsToSpan<const int(&&)[]>());
51 
52 // C arrays convert to span.
53 static_assert(ConvertsToSpan<std::array<int, 5>>());
54 static_assert(ConvertsToSpan<decltype("Hello!")>());
55 
56 static_assert(ConvertsToSpan<bool[1]>());
57 static_assert(ConvertsToSpan<char[35]>());
58 static_assert(ConvertsToSpan<const int[35]>());
59 
60 static_assert(ConvertsToSpan<bool (&)[1]>());
61 static_assert(ConvertsToSpan<char (&)[35]>());
62 static_assert(ConvertsToSpan<const int (&)[35]>());
63 
64 static_assert(ConvertsToSpan<bool(&&)[1]>());
65 static_assert(ConvertsToSpan<bool(&&)[1]>());
66 static_assert(ConvertsToSpan<char(&&)[35]>());
67 static_assert(ConvertsToSpan<const int(&&)[35]>());
68 
69 // Container types convert to span.
70 struct FakeContainer {
datapw::kvs::__anon965cffe80111::FakeContainer71   const char* data() const { return nullptr; }
sizepw::kvs::__anon965cffe80111::FakeContainer72   size_t size() const { return 0; }
73 };
74 
75 static_assert(ConvertsToSpan<FakeContainer>());
76 static_assert(ConvertsToSpan<FakeContainer&>());
77 static_assert(ConvertsToSpan<FakeContainer&&>());
78 static_assert(ConvertsToSpan<const FakeContainer>());
79 static_assert(ConvertsToSpan<const FakeContainer&>());
80 static_assert(ConvertsToSpan<const FakeContainer&&>());
81 
82 static_assert(ConvertsToSpan<std::string_view>());
83 static_assert(ConvertsToSpan<std::string_view&>());
84 static_assert(ConvertsToSpan<std::string_view&&>());
85 
86 static_assert(ConvertsToSpan<const std::string_view>());
87 static_assert(ConvertsToSpan<const std::string_view&>());
88 static_assert(ConvertsToSpan<const std::string_view&&>());
89 
90 // Spans should also convert to span.
91 static_assert(ConvertsToSpan<std::span<int>>());
92 static_assert(ConvertsToSpan<std::span<byte>>());
93 static_assert(ConvertsToSpan<std::span<const int*>>());
94 static_assert(ConvertsToSpan<std::span<bool>&&>());
95 static_assert(ConvertsToSpan<const std::span<bool>&>());
96 static_assert(ConvertsToSpan<std::span<bool>&&>());
97 
98 // These tests for the make_span function were copied from Chromium:
99 // https://chromium.googlesource.com/chromium/src/+/master/base/containers/span_unittest.cc
100 
TEST(SpanTest,MakeSpanFromDataAndSize)101 TEST(SpanTest, MakeSpanFromDataAndSize) {
102   int* nullint = nullptr;
103   auto empty_span = make_span(nullint, 0);
104   EXPECT_TRUE(empty_span.empty());
105   EXPECT_EQ(nullptr, empty_span.data());
106   std::vector<int> vector = {1, 1, 2, 3, 5, 8};
107   span<int> expected_span(vector.data(), vector.size());
108   auto made_span = make_span(vector.data(), vector.size());
109   EXPECT_EQ(expected_span.data(), made_span.data());
110   EXPECT_EQ(expected_span.size(), made_span.size());
111   static_assert(decltype(made_span)::extent == dynamic_extent, "");
112   static_assert(
113       std::is_same<decltype(expected_span), decltype(made_span)>::value,
114       "the type of made_span differs from expected_span!");
115 }
116 
TEST(SpanTest,MakeSpanFromPointerPair)117 TEST(SpanTest, MakeSpanFromPointerPair) {
118   int* nullint = nullptr;
119   auto empty_span = make_span(nullint, nullint);
120   EXPECT_TRUE(empty_span.empty());
121   EXPECT_EQ(nullptr, empty_span.data());
122   std::vector<int> vector = {1, 1, 2, 3, 5, 8};
123   span<int> expected_span(vector.data(), vector.size());
124   auto made_span = make_span(vector.data(), vector.data() + vector.size());
125   EXPECT_EQ(expected_span.data(), made_span.data());
126   EXPECT_EQ(expected_span.size(), made_span.size());
127   static_assert(decltype(made_span)::extent == dynamic_extent, "");
128   static_assert(
129       std::is_same<decltype(expected_span), decltype(made_span)>::value,
130       "the type of made_span differs from expected_span!");
131 }
132 
TEST(SpanTest,MakeSpanFromConstexprArray)133 TEST(SpanTest, MakeSpanFromConstexprArray) {
134   static constexpr int kArray[] = {1, 2, 3, 4, 5};
135   constexpr span<const int, 5> expected_span(kArray);
136   constexpr auto made_span = make_span(kArray);
137   EXPECT_EQ(expected_span.data(), made_span.data());
138   EXPECT_EQ(expected_span.size(), made_span.size());
139   static_assert(decltype(made_span)::extent == 5, "");
140   static_assert(
141       std::is_same<decltype(expected_span), decltype(made_span)>::value,
142       "the type of made_span differs from expected_span!");
143 }
144 
TEST(SpanTest,MakeSpanFromStdArray)145 TEST(SpanTest, MakeSpanFromStdArray) {
146   const std::array<int, 5> kArray = {{1, 2, 3, 4, 5}};
147   span<const int, 5> expected_span(kArray);
148   auto made_span = make_span(kArray);
149   EXPECT_EQ(expected_span.data(), made_span.data());
150   EXPECT_EQ(expected_span.size(), made_span.size());
151   static_assert(decltype(made_span)::extent == 5, "");
152   static_assert(
153       std::is_same<decltype(expected_span), decltype(made_span)>::value,
154       "the type of made_span differs from expected_span!");
155 }
156 
TEST(SpanTest,MakeSpanFromConstContainer)157 TEST(SpanTest, MakeSpanFromConstContainer) {
158   const std::vector<int> vector = {-1, -2, -3, -4, -5};
159   span<const int> expected_span(vector);
160   auto made_span = make_span(vector);
161   EXPECT_EQ(expected_span.data(), made_span.data());
162   EXPECT_EQ(expected_span.size(), made_span.size());
163   static_assert(decltype(made_span)::extent == dynamic_extent, "");
164   static_assert(
165       std::is_same<decltype(expected_span), decltype(made_span)>::value,
166       "the type of made_span differs from expected_span!");
167 }
168 
169 #if 0  // Not currently working with fixed extent spans.
170 
171 TEST(SpanTest, MakeStaticSpanFromConstContainer) {
172   const std::vector<int> vector = {-1, -2, -3, -4, -5};
173   span<const int, 5> expected_span(vector.data(), vector.size());
174   auto made_span = make_span<5>(vector);
175   EXPECT_EQ(expected_span.data(), made_span.data());
176   EXPECT_EQ(expected_span.size(), made_span.size());
177   static_assert(decltype(made_span)::extent == 5, "");
178   static_assert(
179       std::is_same<decltype(expected_span), decltype(made_span)>::value,
180       "the type of made_span differs from expected_span!");
181 }
182 
183 #endif  // 0
184 
TEST(SpanTest,MakeSpanFromContainer)185 TEST(SpanTest, MakeSpanFromContainer) {
186   std::vector<int> vector = {-1, -2, -3, -4, -5};
187   span<int> expected_span(vector);
188   auto made_span = make_span(vector);
189   EXPECT_EQ(expected_span.data(), made_span.data());
190   EXPECT_EQ(expected_span.size(), made_span.size());
191   static_assert(decltype(made_span)::extent == dynamic_extent, "");
192   static_assert(
193       std::is_same<decltype(expected_span), decltype(made_span)>::value,
194       "the type of made_span differs from expected_span!");
195 }
196 
197 #if 0  // Not currently working with fixed extent spans.
198 
199 TEST(SpanTest, MakeStaticSpanFromContainer) {
200   std::vector<int> vector = {-1, -2, -3, -4, -5};
201   span<int, 5> expected_span(vector.data(), vector.size());
202   auto made_span = make_span<5>(vector);
203   EXPECT_EQ(expected_span.data(), make_span<5>(vector).data());
204   EXPECT_EQ(expected_span.size(), make_span<5>(vector).size());
205   static_assert(decltype(make_span<5>(vector))::extent == 5, "");
206   static_assert(
207       std::is_same<decltype(expected_span), decltype(made_span)>::value,
208       "the type of made_span differs from expected_span!");
209 }
210 
211 TEST(SpanTest, MakeStaticSpanFromConstexprContainer) {
212   constexpr StringPiece str = "Hello, World";
213   constexpr auto made_span = make_span<12>(str);
214   static_assert(str.data() == made_span.data(), "Error: data() does not match");
215   static_assert(str.size() == made_span.size(), "Error: size() does not match");
216   static_assert(std::is_same<decltype(str)::value_type,
217                              decltype(made_span)::value_type>::value,
218                 "Error: value_type does not match");
219   static_assert(str.size() == decltype(made_span)::extent,
220                 "Error: extent does not match");
221 }
222 
223 #endif  // 0
224 
TEST(SpanTest,MakeSpanFromRValueContainer)225 TEST(SpanTest, MakeSpanFromRValueContainer) {
226   std::vector<int> vector = {-1, -2, -3, -4, -5};
227   span<const int> expected_span(vector);
228   // Note: While static_cast<T&&>(foo) is effectively just a fancy spelling of
229   // std::move(foo), make_span does not actually take ownership of the passed in
230   // container. Writing it this way makes it more obvious that we simply care
231   // about the right behavour when passing rvalues.
232   auto made_span = make_span(static_cast<std::vector<int>&&>(vector));
233   EXPECT_EQ(expected_span.data(), made_span.data());
234   EXPECT_EQ(expected_span.size(), made_span.size());
235   static_assert(decltype(made_span)::extent == dynamic_extent, "");
236   static_assert(
237       std::is_same<decltype(expected_span), decltype(made_span)>::value,
238       "the type of made_span differs from expected_span!");
239 }
240 
241 #if 0  // Not currently working with fixed extent spans.
242 
243 TEST(SpanTest, MakeStaticSpanFromRValueContainer) {
244   std::vector<int> vector = {-1, -2, -3, -4, -5};
245   span<const int, 5> expected_span(vector.data(), vector.size());
246   // Note: While static_cast<T&&>(foo) is effectively just a fancy spelling of
247   // std::move(foo), make_span does not actually take ownership of the passed in
248   // container. Writing it this way makes it more obvious that we simply care
249   // about the right behavour when passing rvalues.
250   auto made_span = make_span<5>(static_cast<std::vector<int>&&>(vector));
251   EXPECT_EQ(expected_span.data(), made_span.data());
252   EXPECT_EQ(expected_span.size(), made_span.size());
253   static_assert(decltype(made_span)::extent == 5, "");
254   static_assert(
255       std::is_same<decltype(expected_span), decltype(made_span)>::value,
256       "the type of made_span differs from expected_span!");
257 }
258 
259 #endif  // 0
260 
TEST(SpanTest,MakeSpanFromDynamicSpan)261 TEST(SpanTest, MakeSpanFromDynamicSpan) {
262   static constexpr int kArray[] = {1, 2, 3, 4, 5};
263   constexpr span<const int> expected_span(kArray);
264   constexpr auto made_span = make_span(expected_span);
265   static_assert(std::is_same<decltype(expected_span)::element_type,
266                              decltype(made_span)::element_type>::value,
267                 "make_span(span) should have the same element_type as span");
268   static_assert(expected_span.data() == made_span.data(),
269                 "make_span(span) should have the same data() as span");
270   static_assert(expected_span.size() == made_span.size(),
271                 "make_span(span) should have the same size() as span");
272   static_assert(decltype(made_span)::extent == decltype(expected_span)::extent,
273                 "make_span(span) should have the same extent as span");
274   static_assert(
275       std::is_same<decltype(expected_span), decltype(made_span)>::value,
276       "the type of made_span differs from expected_span!");
277 }
278 
TEST(SpanTest,MakeSpanFromStaticSpan)279 TEST(SpanTest, MakeSpanFromStaticSpan) {
280   static constexpr int kArray[] = {1, 2, 3, 4, 5};
281   constexpr span<const int, 5> expected_span(kArray);
282   constexpr auto made_span = make_span(expected_span);
283   static_assert(std::is_same<decltype(expected_span)::element_type,
284                              decltype(made_span)::element_type>::value,
285                 "make_span(span) should have the same element_type as span");
286   static_assert(expected_span.data() == made_span.data(),
287                 "make_span(span) should have the same data() as span");
288   static_assert(expected_span.size() == made_span.size(),
289                 "make_span(span) should have the same size() as span");
290   static_assert(decltype(made_span)::extent == decltype(expected_span)::extent,
291                 "make_span(span) should have the same extent as span");
292   static_assert(
293       std::is_same<decltype(expected_span), decltype(made_span)>::value,
294       "the type of made_span differs from expected_span!");
295 }
296 
297 }  // namespace
298 }  // namespace pw::kvs
299