xref: /aosp_15_r20/external/pigweed/pw_channel/channel_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 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 #include "pw_channel/channel.h"
15 
16 #include <optional>
17 
18 #include "pw_allocator/testing.h"
19 #include "pw_assert/check.h"
20 #include "pw_compilation_testing/negative_compilation.h"
21 #include "pw_multibuf/allocator.h"
22 #include "pw_multibuf/simple_allocator.h"
23 #include "pw_preprocessor/compiler.h"
24 #include "pw_unit_test/framework.h"
25 
26 namespace {
27 
28 using ::pw::allocator::test::AllocatorForTest;
29 using ::pw::async2::Context;
30 using ::pw::async2::Dispatcher;
31 using ::pw::async2::Pending;
32 using ::pw::async2::Poll;
33 using ::pw::async2::Ready;
34 using ::pw::async2::Task;
35 using ::pw::async2::Waker;
36 using ::pw::channel::ByteChannel;
37 using ::pw::channel::DatagramWriter;
38 using ::pw::channel::kReadable;
39 using ::pw::channel::kReliable;
40 using ::pw::channel::kSeekable;
41 using ::pw::channel::kWritable;
42 using ::pw::multibuf::MultiBuf;
43 using ::pw::multibuf::MultiBufAllocationFuture;
44 using ::pw::multibuf::MultiBufAllocator;
45 using ::pw::multibuf::SimpleAllocator;
46 
47 static_assert(sizeof(::pw::channel::AnyChannel) == 2 * sizeof(void*));
48 
49 static_assert((kReliable < kReadable) && (kReadable < kWritable) &&
50               (kWritable < kSeekable));
51 
52 class ReliableByteReaderWriterStub
53     : public pw::channel::ByteChannelImpl<kReliable, kReadable, kWritable> {
54  private:
55   // Read functions
56 
DoPendRead(Context &)57   Poll<pw::Result<pw::multibuf::MultiBuf>> DoPendRead(Context&) override {
58     return Pending();
59   }
60 
61   // Write functions
62 
63   // Disable maybe-uninitialized: this check fails erroniously on Windows GCC.
64   PW_MODIFY_DIAGNOSTICS_PUSH();
65   PW_MODIFY_DIAGNOSTIC_GCC(ignored, "-Wmaybe-uninitialized");
DoPendReadyToWrite(Context &)66   Poll<pw::Status> DoPendReadyToWrite(Context&) override { return Pending(); }
67   PW_MODIFY_DIAGNOSTICS_POP();
68 
DoPendAllocateWriteBuffer(Context &,size_t)69   Poll<std::optional<MultiBuf>> DoPendAllocateWriteBuffer(Context&,
70                                                           size_t) override {
71     return std::nullopt;
72   }
73 
DoStageWrite(pw::multibuf::MultiBuf &&)74   pw::Status DoStageWrite(pw::multibuf::MultiBuf&&) override {
75     return pw::Status::Unimplemented();
76   }
77 
DoPendWrite(Context &)78   Poll<pw::Status> DoPendWrite(Context&) override {
79     return Ready(pw::Status::Unimplemented());
80   }
81 
82   // Common functions
DoPendClose(Context &)83   Poll<pw::Status> DoPendClose(Context&) override { return pw::OkStatus(); }
84 };
85 
86 class ReadOnlyStub : public pw::channel::Implement<pw::channel::ByteReader> {
87  public:
88   constexpr ReadOnlyStub() = default;
89 
90  private:
91   // Read functions
DoPendRead(Context &)92   Poll<pw::Result<pw::multibuf::MultiBuf>> DoPendRead(Context&) override {
93     return Pending();
94   }
95 
DoPendClose(Context &)96   Poll<pw::Status> DoPendClose(Context&) override { return pw::OkStatus(); }
97 };
98 
99 class WriteOnlyStub : public pw::channel::Implement<pw::channel::ByteWriter> {
100  private:
101   // Write functions
102 
DoPendReadyToWrite(Context &)103   Poll<pw::Status> DoPendReadyToWrite(Context&) override { return Pending(); }
104 
DoPendAllocateWriteBuffer(Context &,size_t)105   Poll<std::optional<MultiBuf>> DoPendAllocateWriteBuffer(Context&,
106                                                           size_t) override {
107     return std::nullopt;
108   }
109 
DoStageWrite(pw::multibuf::MultiBuf &&)110   pw::Status DoStageWrite(pw::multibuf::MultiBuf&&) override {
111     return pw::Status::Unimplemented();
112   }
113 
DoPendWrite(Context &)114   Poll<pw::Status> DoPendWrite(Context&) override {
115     return Ready(pw::Status::Unimplemented());
116   }
117 
118   // Common functions
DoPendClose(Context &)119   Poll<pw::Status> DoPendClose(Context&) override { return pw::OkStatus(); }
120 };
121 
TEST(Channel,MethodsShortCircuitAfterCloseReturnsReady)122 TEST(Channel, MethodsShortCircuitAfterCloseReturnsReady) {
123   Dispatcher dispatcher;
124 
125   class : public Task {
126    public:
127     ReliableByteReaderWriterStub channel;
128 
129    private:
130     Poll<> DoPend(Context& cx) override {
131       EXPECT_TRUE(channel.is_read_open());
132       EXPECT_TRUE(channel.is_write_open());
133       EXPECT_EQ(Ready(pw::OkStatus()), channel.PendClose(cx));
134       EXPECT_FALSE(channel.is_read_open());
135       EXPECT_FALSE(channel.is_write_open());
136 
137       EXPECT_EQ(pw::Status::FailedPrecondition(),
138                 channel.PendRead(cx)->status());
139       EXPECT_EQ(Ready(pw::Status::FailedPrecondition()),
140                 channel.PendReadyToWrite(cx));
141       EXPECT_EQ(Ready(pw::Status::FailedPrecondition()), channel.PendWrite(cx));
142       EXPECT_EQ(Ready(pw::Status::FailedPrecondition()), channel.PendClose(cx));
143 
144       return Ready();
145     }
146   } test_task;
147   dispatcher.Post(test_task);
148 
149   EXPECT_TRUE(dispatcher.RunUntilStalled().IsReady());
150 }
151 
TEST(Channel,ReadOnlyChannelOnlyOpenForReads)152 TEST(Channel, ReadOnlyChannelOnlyOpenForReads) {
153   ReadOnlyStub read_only;
154 
155   EXPECT_TRUE(read_only.readable());
156   EXPECT_TRUE(read_only.is_read_open());
157   EXPECT_FALSE(read_only.is_write_open());
158 }
159 
TEST(Channel,WriteOnlyChannelOnlyOpenForWrites)160 TEST(Channel, WriteOnlyChannelOnlyOpenForWrites) {
161   WriteOnlyStub write_only;
162 
163   EXPECT_FALSE(write_only.readable());
164   EXPECT_FALSE(write_only.is_read_open());
165   EXPECT_TRUE(write_only.is_write_open());
166 }
167 
168 #if PW_NC_TEST(ChannelInvalidOrdering)
169 PW_NC_EXPECT("Properties must be specified in the following order");
Illegal(pw::channel::ByteChannel<kReadable,pw::channel::kReliable> & foo)170 bool Illegal(pw::channel::ByteChannel<kReadable, pw::channel::kReliable>& foo) {
171   return foo.is_read_open();
172 }
173 #elif PW_NC_TEST(ChannelImplInvalidOrdering)
174 PW_NC_EXPECT("Properties must be specified in the following order");
175 class BadChannel
176     : public pw::channel::ByteChannelImpl<kReadable, pw::channel::kReliable> {};
177 #elif PW_NC_TEST(ChannelNoProperties)
178 PW_NC_EXPECT("At least one of kReadable or kWritable must be provided");
Illegal(pw::channel::ByteChannel<> & foo)179 bool Illegal(pw::channel::ByteChannel<>& foo) { return foo.is_read_open(); }
180 #elif PW_NC_TEST(ChannelImplNoProperties)
181 PW_NC_EXPECT("At least one of kReadable or kWritable must be provided");
182 class NoChannel : public pw::channel::ByteChannelImpl<> {};
183 #elif PW_NC_TEST(ChannelNoReadOrWrite)
184 PW_NC_EXPECT("At least one of kReadable or kWritable must be provided");
Illegal(pw::channel::ByteChannel<pw::channel::kReliable> & foo)185 bool Illegal(pw::channel::ByteChannel<pw::channel::kReliable>& foo) {
186   return foo.is_read_open();
187 }
188 #elif PW_NC_TEST(ChannelImplNoReadOrWrite)
189 PW_NC_EXPECT("At least one of kReadable or kWritable must be provided");
190 class BadChannel : public pw::channel::ByteChannelImpl<pw::channel::kReliable> {
191 };
192 #elif PW_NC_TEST(TooMany)
193 PW_NC_EXPECT("Too many properties given");
Illegal(pw::channel::ByteChannel<kReliable,kReliable,kReliable,kReadable,kWritable> & foo)194 bool Illegal(
195     pw::channel::
196         ByteChannel<kReliable, kReliable, kReliable, kReadable, kWritable>&
197             foo) {
198   return foo.is_read_open();
199 }
200 #elif PW_NC_TEST(Duplicates)
201 PW_NC_EXPECT("duplicates");
Illegal(pw::channel::ByteChannel<kReadable,kReadable> & foo)202 bool Illegal(pw::channel::ByteChannel<kReadable, kReadable>& foo) {
203   return foo.is_read_open();
204 }
205 #endif  // PW_NC_TEST
206 
207 class TestByteReader
208     : public pw::channel::ByteChannelImpl<kReliable, kReadable> {
209  public:
TestByteReader()210   TestByteReader() {}
211 
PushData(MultiBuf data)212   void PushData(MultiBuf data) {
213     bool was_empty = data_.empty();
214     data_.PushSuffix(std::move(data));
215     if (was_empty) {
216       std::move(read_waker_).Wake();
217     }
218   }
219 
220  private:
DoPendRead(Context & cx)221   Poll<pw::Result<MultiBuf>> DoPendRead(Context& cx) override {
222     if (data_.empty()) {
223       PW_ASYNC_STORE_WAKER(
224           cx, read_waker_, "TestByteReader is waiting for a call to PushData");
225       return Pending();
226     }
227     return std::move(data_);
228   }
229 
DoPendClose(Context &)230   Poll<pw::Status> DoPendClose(Context&) override {
231     return Ready(pw::OkStatus());
232   }
233 
234   Waker read_waker_;
235   MultiBuf data_;
236 };
237 
238 class TestDatagramWriter : public pw::channel::Implement<DatagramWriter> {
239  public:
TestDatagramWriter(MultiBufAllocator & alloc)240   TestDatagramWriter(MultiBufAllocator& alloc) : alloc_fut_(alloc) {}
241 
last_datagram() const242   const pw::multibuf::MultiBuf& last_datagram() const { return last_dgram_; }
243 
MakeReadyToWrite()244   void MakeReadyToWrite() {
245     PW_CHECK_INT_EQ(
246         state_,
247         kUnavailable,
248         "Can't make writable when write is pending or already writable");
249 
250     state_ = kReadyToWrite;
251     std::move(waker_).Wake();
252   }
253 
MakeReadyToFlush()254   void MakeReadyToFlush() {
255     PW_CHECK_INT_EQ(state_,
256                     kWritePending,
257                     "Can't make flushable unless a write is pending");
258 
259     state_ = kReadyToFlush;
260     std::move(waker_).Wake();
261   }
262 
263  private:
DoPendReadyToWrite(Context & cx)264   Poll<pw::Status> DoPendReadyToWrite(Context& cx) override {
265     if (state_ == kReadyToWrite) {
266       return Ready(pw::OkStatus());
267     }
268 
269     PW_ASYNC_STORE_WAKER(
270         cx,
271         waker_,
272         "TestDatagramWriter waiting for a call to MakeReadyToWrite");
273     return Pending();
274   }
275 
DoStageWrite(MultiBuf && buffer)276   pw::Status DoStageWrite(MultiBuf&& buffer) override {
277     if (state_ != kReadyToWrite) {
278       return pw::Status::Unavailable();
279     }
280 
281     state_ = kWritePending;
282     last_dgram_ = std::move(buffer);
283     return pw::OkStatus();
284   }
285 
DoPendAllocateWriteBuffer(Context & cx,size_t min_bytes)286   Poll<std::optional<MultiBuf>> DoPendAllocateWriteBuffer(
287       Context& cx, size_t min_bytes) override {
288     alloc_fut_.SetDesiredSize(min_bytes);
289     return alloc_fut_.Pend(cx);
290   }
291 
DoPendWrite(Context & cx)292   Poll<pw::Status> DoPendWrite(Context& cx) override {
293     if (state_ != kReadyToFlush) {
294       PW_ASYNC_STORE_WAKER(
295           cx, waker_, "TestDatagramWriter is waiting for its Channel to flush");
296       return Pending();
297     }
298     last_flush_ = last_write_;
299     return pw::OkStatus();
300   }
301 
DoPendClose(Context &)302   Poll<pw::Status> DoPendClose(Context&) override {
303     return Ready(pw::OkStatus());
304   }
305 
306   enum {
307     kUnavailable,
308     kReadyToWrite,
309     kWritePending,
310     kReadyToFlush,
311   } state_ = kUnavailable;
312   Waker waker_;
313   uint32_t last_write_ = 0;
314   uint32_t last_flush_ = 0;
315   MultiBuf last_dgram_;
316   MultiBufAllocationFuture alloc_fut_;
317 };
318 
TEST(Channel,TestByteReader)319 TEST(Channel, TestByteReader) {
320   static constexpr char kReadData[] = "hello, world";
321   static constexpr size_t kReadDataSize = sizeof(kReadData);
322   static constexpr size_t kArbitraryMetaSize = 512;
323 
324   Dispatcher dispatcher;
325   std::array<std::byte, kReadDataSize> data_area;
326   AllocatorForTest<kArbitraryMetaSize> meta_alloc;
327   SimpleAllocator simple_allocator(data_area, meta_alloc);
328   std::optional<MultiBuf> read_buf_opt =
329       simple_allocator.Allocate(kReadDataSize);
330   ASSERT_TRUE(read_buf_opt.has_value());
331   MultiBuf& read_buf = *read_buf_opt;
332 
333   class : public Task {
334    public:
335     TestByteReader channel;
336     int test_executed = 0;
337 
338    private:
339     Poll<> DoPend(Context& cx) override {
340       auto result = channel.PendRead(cx);
341       if (!result.IsReady()) {
342         return Pending();
343       }
344 
345       auto actual_result = std::move(*result);
346       EXPECT_TRUE(actual_result.ok());
347 
348       std::byte contents[kReadDataSize] = {};
349 
350       EXPECT_EQ(actual_result->size(), sizeof(kReadData));
351       std::copy(actual_result->begin(), actual_result->end(), contents);
352       EXPECT_STREQ(reinterpret_cast<const char*>(contents), kReadData);
353 
354       test_executed += 1;
355       return Ready();
356     }
357   } test_task;
358 
359   dispatcher.Post(test_task);
360 
361   EXPECT_FALSE(dispatcher.RunUntilStalled().IsReady());
362 
363   auto kReadDataBytes = reinterpret_cast<const std::byte*>(kReadData);
364   std::copy(kReadDataBytes, kReadDataBytes + kReadDataSize, read_buf.begin());
365   test_task.channel.PushData(std::move(read_buf));
366   EXPECT_TRUE(dispatcher.RunUntilStalled().IsReady());
367 
368   EXPECT_EQ(test_task.test_executed, 1);
369 }
370 
TEST(Channel,TestDatagramWriter)371 TEST(Channel, TestDatagramWriter) {
372   Dispatcher dispatcher;
373   static constexpr size_t kArbitraryDataSize = 128;
374   static constexpr size_t kArbitraryMetaSize = 512;
375   std::array<std::byte, kArbitraryDataSize> data_area;
376   AllocatorForTest<kArbitraryMetaSize> meta_alloc;
377   SimpleAllocator simple_allocator(data_area, meta_alloc);
378   TestDatagramWriter write_channel(simple_allocator);
379 
380   static constexpr char kWriteData[] = "Hello there";
381 
382   class SendWriteDataAndFlush : public Task {
383    public:
384     explicit SendWriteDataAndFlush(DatagramWriter& channel, size_t)
385         : channel_(channel) {}
386     int test_executed = 0;
387 
388    private:
389     Poll<> DoPend(Context& cx) override {
390       switch (state_) {
391         case kWaitUntilReady: {
392           if (channel_.PendReadyToWrite(cx).IsPending()) {
393             return Pending();
394           }
395           Poll<std::optional<MultiBuf>> buffer =
396               channel_.PendAllocateWriteBuffer(cx, sizeof(kWriteData));
397           if (buffer.IsPending()) {
398             return Pending();
399           }
400           if (!buffer->has_value()) {
401             // Allocator should have enough space for `kWriteData`.
402             ADD_FAILURE();
403             return Ready();
404           }
405           pw::ConstByteSpan str(pw::as_bytes(pw::span(kWriteData)));
406           std::copy(str.begin(), str.end(), (**buffer).begin());
407           pw::Status write_status = channel_.StageWrite(std::move(**buffer));
408           PW_CHECK_OK(write_status);
409           state_ = kFlushPacket;
410           [[fallthrough]];
411         }
412         case kFlushPacket: {
413           auto result = channel_.PendWrite(cx);
414           if (result.IsPending()) {
415             return Pending();
416           }
417           test_executed += 1;
418           state_ = kWaitUntilReady;
419           return Ready();
420         }
421         default:
422           PW_CRASH("Illegal value");
423       }
424 
425       // This test is INCOMPLETE.
426 
427       test_executed += 1;
428       return Ready();
429     }
430 
431     enum { kWaitUntilReady, kFlushPacket } state_ = kWaitUntilReady;
432     DatagramWriter& channel_;
433   };
434 
435   SendWriteDataAndFlush test_task(write_channel.channel(), 24601);
436   dispatcher.Post(test_task);
437 
438   EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
439   EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
440 
441   write_channel.MakeReadyToWrite();
442 
443   EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
444   EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
445 
446   write_channel.MakeReadyToFlush();
447 
448   EXPECT_EQ(dispatcher.RunUntilStalled(), Ready());
449   EXPECT_EQ(test_task.test_executed, 1);
450 
451   std::byte contents[64] = {};
452   const MultiBuf& dgram = write_channel.last_datagram();
453   std::copy(dgram.begin(), dgram.end(), contents);
454   EXPECT_STREQ(reinterpret_cast<const char*>(contents), kWriteData);
455 }
456 
TakesAChannel(const pw::channel::AnyChannel &)457 void TakesAChannel(const pw::channel::AnyChannel&) {}
458 
TakesAReadableByteChannel(const pw::channel::ByteChannel<kReadable> & channel)459 const pw::channel::ByteChannel<kReadable>& TakesAReadableByteChannel(
460     const pw::channel::ByteChannel<kReadable>& channel) {
461   return channel;
462 }
463 
TakesAWritableByteChannel(const pw::channel::ByteChannel<kWritable> &)464 void TakesAWritableByteChannel(const pw::channel::ByteChannel<kWritable>&) {}
465 
TEST(Channel,Conversions)466 TEST(Channel, Conversions) {
467   static constexpr size_t kArbitraryDataSize = 128;
468   static constexpr size_t kArbitraryMetaSize = 128;
469   std::array<std::byte, kArbitraryDataSize> data_area;
470   AllocatorForTest<kArbitraryMetaSize> meta_alloc;
471   SimpleAllocator simple_allocator(data_area, meta_alloc);
472 
473   const TestByteReader byte_channel;
474   const TestDatagramWriter datagram_channel(simple_allocator);
475 
476   TakesAReadableByteChannel(byte_channel.channel());
477 
478   TakesAReadableByteChannel(byte_channel.as<kReadable>());
479   TakesAReadableByteChannel(byte_channel.channel().as<kReadable>());
480 
481   TakesAReadableByteChannel(byte_channel.as<pw::channel::ByteReader>());
482   TakesAReadableByteChannel(
483       byte_channel.channel().as<pw::channel::ByteReader>());
484 
485   TakesAReadableByteChannel(
486       byte_channel.as<pw::channel::ByteChannel<kReliable, kReadable>>());
487   TakesAReadableByteChannel(
488       byte_channel.channel()
489           .as<pw::channel::ByteChannel<kReliable, kReadable>>());
490 
491   TakesAChannel(byte_channel);
492   TakesAChannel(byte_channel.as<pw::channel::AnyChannel>());
493 
494   TakesAWritableByteChannel(datagram_channel.IgnoreDatagramBoundaries());
495   TakesAWritableByteChannel(
496       datagram_channel.channel().IgnoreDatagramBoundaries());
497 
498   [[maybe_unused]] const pw::channel::AnyChannel& plain = byte_channel;
499 
500 #if PW_NC_TEST(CannotImplicitlyLoseWritability)
501   PW_NC_EXPECT("no matching function for call");
502   TakesAWritableByteChannel(byte_channel.channel());
503 #elif PW_NC_TEST(CannotExplicitlyLoseWritability)
504   PW_NC_EXPECT("Cannot use a non-writable channel as a writable channel");
505   TakesAWritableByteChannel(byte_channel.as<kWritable>());
506 #elif PW_NC_TEST(CannotIgnoreDatagramBoundariesOnByteChannel)
507   PW_NC_EXPECT("only be called to use a datagram channel to a byte channel");
508   std::ignore = byte_channel.IgnoreDatagramBoundaries();
509 #elif PW_NC_TEST(CannotIgnoreDatagramBoundariesOnByteChannelImpl)
510   PW_NC_EXPECT("only be called to use a datagram channel to a byte channel");
511   std::ignore = byte_channel.channel().IgnoreDatagramBoundaries();
512 #endif  // PW_NC_TEST
513 }
514 
515 #if PW_NC_TEST(CannotImplicitlyUseDatagramChannelAsByteChannel)
516 PW_NC_EXPECT("no matching function for call");
DatagramChannelNcTest(pw::channel::DatagramChannel<kReliable,kReadable> & dgram)517 void DatagramChannelNcTest(
518     pw::channel::DatagramChannel<kReliable, kReadable>& dgram) {
519   TakesAReadableByteChannel(dgram);
520 }
521 #elif PW_NC_TEST(CannotExplicitlyUseDatagramChannelAsByteChannel)
522 PW_NC_EXPECT("Datagram and byte channels are not interchangeable");
DatagramChannelNcTest(pw::channel::DatagramChannel<kReliable,kReadable> & dgram)523 void DatagramChannelNcTest(
524     pw::channel::DatagramChannel<kReliable, kReadable>& dgram) {
525   TakesAReadableByteChannel(dgram.as<pw::channel::ByteChannel<kReadable>>());
526 }
527 #endif  // PW_NC_TEST
528 
529 class Foo {
530  public:
Foo(pw::channel::ByteChannel<kReadable> &)531   Foo(pw::channel::ByteChannel<kReadable>&) {}
532   Foo(const Foo&) = default;
533 };
534 
535 // Define additional overloads to ensure the right overload is selected with the
536 // implicit conversion.
TakesAReadableByteChannel(const Foo &)537 [[maybe_unused]] void TakesAReadableByteChannel(const Foo&) {}
TakesAReadableByteChannel(int)538 [[maybe_unused]] void TakesAReadableByteChannel(int) {}
TakesAReadableByteChannel(const pw::channel::DatagramReaderWriter &)539 [[maybe_unused]] void TakesAReadableByteChannel(
540     const pw::channel::DatagramReaderWriter&) {}
541 
TEST(Channel,SelectsCorrectOverloadWhenRelyingOnImplicitConversion)542 TEST(Channel, SelectsCorrectOverloadWhenRelyingOnImplicitConversion) {
543   TestByteReader byte_channel;
544 
545   [[maybe_unused]] Foo selects_channel_ctor_not_copy_ctor(
546       byte_channel.channel());
547   EXPECT_EQ(&byte_channel.as<pw::channel::ByteChannel<kReadable>>(),
548             &TakesAReadableByteChannel(byte_channel.channel()));
549 }
550 
551 #if PW_NC_TEST(CannotCallUnsupportedWriteMethodsOnChannel)
552 PW_NC_EXPECT("PendReadyToWrite may only be called on writable channels");
Bad(Context & cx,pw::channel::DatagramReader & c)553 [[maybe_unused]] void Bad(Context& cx, pw::channel::DatagramReader& c) {
554   std::ignore = c.PendReadyToWrite(cx);
555 }
556 #elif PW_NC_TEST(CannotCallUnsupportedWriteMethodsOnChannelImpl)
557 PW_NC_EXPECT("PendReadyToWrite may only be called on writable channels");
Bad(Context & cx,pw::channel::ByteReaderImpl & c)558 [[maybe_unused]] void Bad(Context& cx, pw::channel::ByteReaderImpl& c) {
559   std::ignore = c.PendReadyToWrite(cx);
560 }
561 #elif PW_NC_TEST(CannotCallUnsupportedReadMethodsOnChannel)
562 PW_NC_EXPECT("PendRead may only be called on readable channels");
Bad(Context & cx,pw::channel::ByteWriter & c)563 [[maybe_unused]] void Bad(Context& cx, pw::channel::ByteWriter& c) {
564   std::ignore = c.PendRead(cx);
565 }
566 #elif PW_NC_TEST(CannotCallUnsupportedReadMethodsOnChannelImpl)
567 PW_NC_EXPECT("PendRead may only be called on readable channels");
Bad(Context & cx,pw::channel::DatagramWriterImpl & c)568 [[maybe_unused]] void Bad(Context& cx, pw::channel::DatagramWriterImpl& c) {
569   std::ignore = c.PendRead(cx);
570 }
571 #endif  // PW_NC_TEST
572 
573 }  // namespace
574