Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 120 additions & 1 deletion crates/nucleus-test-sdk/src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ impl Serial {
match p.read(&mut buf) {
Ok(0) => Ok(None),
Ok(_) => Ok(Some(buf[0])),
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => Ok(None),
Err(e)
if e.kind() == std::io::ErrorKind::WouldBlock
|| e.kind() == std::io::ErrorKind::TimedOut =>
{
Ok(None)
}
Err(e) => Err(e),
}
}
Expand Down Expand Up @@ -105,4 +110,118 @@ mod tests {
let mut s = Serial::open_tcp(&addr.to_string()).unwrap();
assert_eq!(s.read_byte(Duration::from_millis(50)).unwrap(), None);
}

/// A `serialport::SerialPort` stub whose `read` always returns
/// `ErrorKind::WouldBlock` — some serialport backends report a timed-out
/// read this way instead of `ErrorKind::TimedOut`.
struct WouldBlockPort;

impl std::io::Read for WouldBlockPort {
fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
Err(std::io::Error::from(std::io::ErrorKind::WouldBlock))
}
}

impl std::io::Write for WouldBlockPort {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}

impl serialport::SerialPort for WouldBlockPort {
fn name(&self) -> Option<String> {
None
}
fn baud_rate(&self) -> serialport::Result<u32> {
Ok(115200)
}
fn data_bits(&self) -> serialport::Result<serialport::DataBits> {
Ok(serialport::DataBits::Eight)
}
fn flow_control(&self) -> serialport::Result<serialport::FlowControl> {
Ok(serialport::FlowControl::None)
}
fn parity(&self) -> serialport::Result<serialport::Parity> {
Ok(serialport::Parity::None)
}
fn stop_bits(&self) -> serialport::Result<serialport::StopBits> {
Ok(serialport::StopBits::One)
}
fn timeout(&self) -> Duration {
Duration::from_millis(50)
}
fn set_baud_rate(&mut self, _baud_rate: u32) -> serialport::Result<()> {
Ok(())
}
fn set_data_bits(&mut self, _data_bits: serialport::DataBits) -> serialport::Result<()> {
Ok(())
}
fn set_flow_control(
&mut self,
_flow_control: serialport::FlowControl,
) -> serialport::Result<()> {
Ok(())
}
fn set_parity(&mut self, _parity: serialport::Parity) -> serialport::Result<()> {
Ok(())
}
fn set_stop_bits(&mut self, _stop_bits: serialport::StopBits) -> serialport::Result<()> {
Ok(())
}
fn set_timeout(&mut self, _timeout: Duration) -> serialport::Result<()> {
Ok(())
}
fn write_request_to_send(&mut self, _level: bool) -> serialport::Result<()> {
Ok(())
}
fn write_data_terminal_ready(&mut self, _level: bool) -> serialport::Result<()> {
Ok(())
}
fn read_clear_to_send(&mut self) -> serialport::Result<bool> {
Ok(false)
}
fn read_data_set_ready(&mut self) -> serialport::Result<bool> {
Ok(false)
}
fn read_ring_indicator(&mut self) -> serialport::Result<bool> {
Ok(false)
}
fn read_carrier_detect(&mut self) -> serialport::Result<bool> {
Ok(false)
}
fn bytes_to_read(&self) -> serialport::Result<u32> {
Ok(0)
}
fn bytes_to_write(&self) -> serialport::Result<u32> {
Ok(0)
}
fn clear(&self, _buffer_to_clear: serialport::ClearBuffer) -> serialport::Result<()> {
Ok(())
}
fn try_clone(&self) -> serialport::Result<Box<dyn serialport::SerialPort>> {
Err(serialport::Error::new(
serialport::ErrorKind::Unknown,
"clone not supported in test stub",
))
}
fn set_break(&self) -> serialport::Result<()> {
Ok(())
}
fn clear_break(&self) -> serialport::Result<()> {
Ok(())
}
}

#[test]
fn port_read_byte_treats_would_block_as_a_timeout_not_an_error() {
// Issue #51: the `Port` branch only caught `ErrorKind::TimedOut`,
// unlike the `Tcp` branch's `TimedOut | WouldBlock`. Some
// serialport backends report a timed-out read as `WouldBlock`,
// which used to surface as `Err` here instead of `Ok(None)`.
let mut s = Serial::Port(Box::new(WouldBlockPort));
assert_eq!(s.read_byte(Duration::from_millis(10)).unwrap(), None);
}
}
Loading