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