• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 "pw_stream/stream.h"
16 
17 #include <limits>
18 
19 #include "gtest/gtest.h"
20 
21 namespace pw::stream {
22 namespace {
23 
24 static_assert(sizeof(Stream) <= 2 * sizeof(void*),
25               "Stream should be no larger than two pointers (vtable pointer & "
26               "packed members)");
27 
28 class TestNonSeekableReader : public NonSeekableReader {
29  private:
DoRead(ByteSpan)30   StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
31 };
32 
33 class TestRelativeSeekableReader : public RelativeSeekableReader {
34  private:
DoRead(ByteSpan)35   StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
DoSeek(ptrdiff_t,Whence)36   Status DoSeek(ptrdiff_t, Whence) override { return Status(); }
37 };
38 
39 class TestSeekableReader : public SeekableReader {
40  private:
DoRead(ByteSpan)41   StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
DoSeek(ptrdiff_t,Whence)42   Status DoSeek(ptrdiff_t, Whence) override { return Status(); }
43 };
44 
45 class TestNonSeekableWriter : public NonSeekableWriter {
46  private:
DoWrite(ConstByteSpan)47   Status DoWrite(ConstByteSpan) override { return OkStatus(); }
48 };
49 
50 class TestRelativeSeekableWriter : public RelativeSeekableWriter {
51  private:
DoWrite(ConstByteSpan)52   Status DoWrite(ConstByteSpan) override { return OkStatus(); }
DoSeek(ptrdiff_t,Whence)53   Status DoSeek(ptrdiff_t, Whence) override { return OkStatus(); }
54 };
55 
56 class TestSeekableWriter : public SeekableWriter {
57  private:
DoWrite(ConstByteSpan)58   Status DoWrite(ConstByteSpan) override { return OkStatus(); }
DoSeek(ptrdiff_t,Whence)59   Status DoSeek(ptrdiff_t, Whence) override { return OkStatus(); }
60 };
61 
62 class TestNonSeekableReaderWriter : public NonSeekableReaderWriter {
63  private:
DoRead(ByteSpan)64   StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
DoWrite(ConstByteSpan)65   Status DoWrite(ConstByteSpan) override { return OkStatus(); }
66 };
67 
68 class TestRelativeSeekableReaderWriter : public RelativeSeekableReaderWriter {
69  private:
DoRead(ByteSpan)70   StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
DoWrite(ConstByteSpan)71   Status DoWrite(ConstByteSpan) override { return OkStatus(); }
DoSeek(ptrdiff_t,Whence)72   Status DoSeek(ptrdiff_t, Whence) override { return OkStatus(); }
73 };
74 
75 class TestSeekableReaderWriter : public SeekableReaderWriter {
76  private:
DoRead(ByteSpan)77   StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
DoWrite(ConstByteSpan)78   Status DoWrite(ConstByteSpan) override { return OkStatus(); }
DoSeek(ptrdiff_t,Whence)79   Status DoSeek(ptrdiff_t, Whence) override { return OkStatus(); }
80 };
81 
82 // Test ReaderWriter conversions to Reader/Writer.
83 // clang-format off
84 static_assert(std::is_convertible<TestNonSeekableReaderWriter, Reader&>());
85 static_assert(std::is_convertible<TestNonSeekableReaderWriter, Writer&>());
86 static_assert(!std::is_convertible<TestNonSeekableReaderWriter, RelativeSeekableReader&>());
87 static_assert(!std::is_convertible<TestNonSeekableReaderWriter, RelativeSeekableWriter&>());
88 static_assert(!std::is_convertible<TestNonSeekableReaderWriter, SeekableWriter&>());
89 static_assert(!std::is_convertible<TestNonSeekableReaderWriter, SeekableReader&>());
90 
91 static_assert(std::is_convertible<TestRelativeSeekableReaderWriter, Reader&>());
92 static_assert(std::is_convertible<TestRelativeSeekableReaderWriter, Writer&>());
93 static_assert(std::is_convertible<TestRelativeSeekableReaderWriter, RelativeSeekableReader&>());
94 static_assert(std::is_convertible<TestRelativeSeekableReaderWriter, RelativeSeekableWriter&>());
95 static_assert(!std::is_convertible<TestRelativeSeekableReaderWriter, SeekableWriter&>());
96 static_assert(!std::is_convertible<TestRelativeSeekableReaderWriter, SeekableReader&>());
97 
98 static_assert(std::is_convertible<TestSeekableReaderWriter, Reader&>());
99 static_assert(std::is_convertible<TestSeekableReaderWriter, Writer&>());
100 static_assert(std::is_convertible<TestSeekableReaderWriter, RelativeSeekableReader&>());
101 static_assert(std::is_convertible<TestSeekableReaderWriter, RelativeSeekableWriter&>());
102 static_assert(std::is_convertible<TestSeekableReaderWriter, SeekableWriter&>());
103 static_assert(std::is_convertible<TestSeekableReaderWriter, SeekableReader&>());
104 // clang-format on
105 
106 constexpr uint8_t kSeekable =
107     Stream::kBeginning | Stream::kCurrent | Stream::kEnd;
108 constexpr uint8_t kRelativeSeekable = Stream::kCurrent;
109 constexpr uint8_t kNonSeekable = 0;
110 
111 enum Readable : bool { kNonReadable = false, kReadable = true };
112 enum Writable : bool { kNonWritable = false, kWritable = true };
113 
114 template <typename T, Readable readable, Writable writable, uint8_t seekable>
TestStreamImpl()115 void TestStreamImpl() {
116   T derived_stream;
117   Stream& stream = derived_stream;
118 
119   // Check stream properties
120   ASSERT_EQ(writable, stream.writable());
121   ASSERT_EQ(readable, stream.readable());
122 
123   ASSERT_EQ((seekable & Stream::kBeginning) != 0,
124             stream.seekable(Stream::kBeginning));
125   ASSERT_EQ((seekable & Stream::kCurrent) != 0,
126             stream.seekable(Stream::kCurrent));
127   ASSERT_EQ((seekable & Stream::kEnd) != 0, stream.seekable(Stream::kEnd));
128 
129   ASSERT_EQ(seekable != kNonSeekable, stream.seekable());
130 
131   // Check Read()/Write()/Seek()
132   ASSERT_EQ(readable ? OkStatus() : Status::Unimplemented(),
133             stream.Read({}).status());
134   ASSERT_EQ(writable ? OkStatus() : Status::Unimplemented(), stream.Write({}));
135   ASSERT_EQ(seekable ? OkStatus() : Status::Unimplemented(), stream.Seek(0));
136 
137   // Check ConservativeLimits()
138   ASSERT_EQ(readable ? Stream::kUnlimited : 0, stream.ConservativeReadLimit());
139   ASSERT_EQ(writable ? Stream::kUnlimited : 0, stream.ConservativeWriteLimit());
140 }
141 
TEST(Stream,NonSeekableReader)142 TEST(Stream, NonSeekableReader) {
143   TestStreamImpl<TestNonSeekableReader,
144                  kReadable,
145                  kNonWritable,
146                  kNonSeekable>();
147 }
148 
TEST(Stream,RelativeSeekableReader)149 TEST(Stream, RelativeSeekableReader) {
150   TestStreamImpl<TestRelativeSeekableReader,
151                  kReadable,
152                  kNonWritable,
153                  kRelativeSeekable>();
154 }
155 
TEST(Stream,SeekableReader)156 TEST(Stream, SeekableReader) {
157   TestStreamImpl<TestSeekableReader, kReadable, kNonWritable, kSeekable>();
158 }
159 
TEST(Stream,NonSeekableWriter)160 TEST(Stream, NonSeekableWriter) {
161   TestStreamImpl<TestNonSeekableWriter,
162                  kNonReadable,
163                  kWritable,
164                  kNonSeekable>();
165 }
166 
TEST(Stream,RelativeSeekableWriter)167 TEST(Stream, RelativeSeekableWriter) {
168   TestStreamImpl<TestRelativeSeekableWriter,
169                  kNonReadable,
170                  kWritable,
171                  kRelativeSeekable>();
172 }
173 
TEST(Stream,SeekableWriter)174 TEST(Stream, SeekableWriter) {
175   TestStreamImpl<TestSeekableWriter, kNonReadable, kWritable, kSeekable>();
176 }
177 
TEST(Stream,NonSeekableReaderWriter)178 TEST(Stream, NonSeekableReaderWriter) {
179   TestStreamImpl<TestNonSeekableReaderWriter,
180                  kReadable,
181                  kWritable,
182                  kNonSeekable>();
183 }
184 
TEST(Stream,RelativeSeekableReaderWriter)185 TEST(Stream, RelativeSeekableReaderWriter) {
186   TestStreamImpl<TestRelativeSeekableReaderWriter,
187                  kReadable,
188                  kWritable,
189                  kRelativeSeekable>();
190 }
191 
TEST(Stream,SeekableReaderWriter)192 TEST(Stream, SeekableReaderWriter) {
193   TestStreamImpl<TestSeekableReaderWriter, kReadable, kWritable, kSeekable>();
194 }
195 
196 }  // namespace
197 }  // namespace pw::stream
198