blob: 68fc5b2c0acabaf3503ca81419098e6cf5638764 [file] [log] [blame]
Wyatt Hepler2debeb62020-12-03 08:19:57 -08001// 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
24namespace pw::kvs {
25namespace {
26
27using internal::make_span;
28using std::byte;
29using std::dynamic_extent;
30using 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.
36struct Foo {};
37
38static_assert(!ConvertsToSpan<Foo>());
39static_assert(!ConvertsToSpan<int>());
40static_assert(!ConvertsToSpan<void>());
41static_assert(!ConvertsToSpan<byte>());
42static_assert(!ConvertsToSpan<byte*>());
43
44// Arrays without an extent are just pointers -- these should not convert.
45static_assert(!ConvertsToSpan<bool[]>());
46static_assert(!ConvertsToSpan<const int[]>());
47static_assert(!ConvertsToSpan<bool (&)[]>());
48static_assert(!ConvertsToSpan<const int (&)[]>());
49static_assert(!ConvertsToSpan<bool(&&)[]>());
50static_assert(!ConvertsToSpan<const int(&&)[]>());
51
52// C arrays convert to span.
53static_assert(ConvertsToSpan<std::array<int, 5>>());
54static_assert(ConvertsToSpan<decltype("Hello!")>());
55
56static_assert(ConvertsToSpan<bool[1]>());
57static_assert(ConvertsToSpan<char[35]>());
58static_assert(ConvertsToSpan<const int[35]>());
59
60static_assert(ConvertsToSpan<bool (&)[1]>());
61static_assert(ConvertsToSpan<char (&)[35]>());
62static_assert(ConvertsToSpan<const int (&)[35]>());
63
64static_assert(ConvertsToSpan<bool(&&)[1]>());
65static_assert(ConvertsToSpan<bool(&&)[1]>());
66static_assert(ConvertsToSpan<char(&&)[35]>());
67static_assert(ConvertsToSpan<const int(&&)[35]>());
68
69// Container types convert to span.
70struct FakeContainer {
71 const char* data() const { return nullptr; }
72 size_t size() const { return 0; }
73};
74
75static_assert(ConvertsToSpan<FakeContainer>());
76static_assert(ConvertsToSpan<FakeContainer&>());
77static_assert(ConvertsToSpan<FakeContainer&&>());
78static_assert(ConvertsToSpan<const FakeContainer>());
79static_assert(ConvertsToSpan<const FakeContainer&>());
80static_assert(ConvertsToSpan<const FakeContainer&&>());
81
82static_assert(ConvertsToSpan<std::string_view>());
83static_assert(ConvertsToSpan<std::string_view&>());
84static_assert(ConvertsToSpan<std::string_view&&>());
85
86static_assert(ConvertsToSpan<const std::string_view>());
87static_assert(ConvertsToSpan<const std::string_view&>());
88static_assert(ConvertsToSpan<const std::string_view&&>());
89
90// Spans should also convert to span.
91static_assert(ConvertsToSpan<std::span<int>>());
92static_assert(ConvertsToSpan<std::span<byte>>());
93static_assert(ConvertsToSpan<std::span<const int*>>());
94static_assert(ConvertsToSpan<std::span<bool>&&>());
95static_assert(ConvertsToSpan<const std::span<bool>&>());
96static_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
101TEST(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
117TEST(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
133TEST(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
145TEST(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
157TEST(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
171TEST(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
185TEST(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
199TEST(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
211TEST(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
225TEST(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
243TEST(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
261TEST(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
279TEST(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