1
Fork 0

Added a few tests and got them working. Added feature "trace".

This commit is contained in:
Alex Helfet 2017-12-21 04:17:59 +00:00
parent 2349c9e087
commit 40366a6afe
3 changed files with 109 additions and 14 deletions

View file

@ -11,4 +11,11 @@ repository = "https://github.com/fluffysquirrels/framed"
[dependencies]
cobs = "^0.1.2"
error-chain = "^0.11.0"
error-chain = "^0.11.0"
ref_slice = "^1.1.1"
[features]
default_features = []
# Enable to print all data to stdout for testing.
trace = []

View file

@ -12,5 +12,9 @@ error_chain! {
description("COBS decode failed"),
display("COBS decode failed"),
}
EofDuringFrame {
description("end of file during a frame"),
display("end of file during a frame"),
}
}
}

View file

@ -8,8 +8,19 @@
//!
//! [dll]: https://en.wikipedia.org/wiki/Data_link_layer
//! [pl]: https://en.wikipedia.org/wiki/Physical_layer
// TODO: Make this work when no_std.
//!
//! Currently the encoding is: the frame [COBS]-encoded
//! to remove bytes equal to zero, then a terminating zero byte.
//! [COBS]: https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
//!
//! ## Cargo feature flags
//! `trace`: Enable to print all data to stdout for testing.
//!
//! ## TODO
//! * Start frame with a zero as well, then we detect partial frames.
//! * Add a length field to the beginning of the frame and a
//! checksum to the end. Perhaps make them optional.
//! * Support no_std.
#![deny(warnings)]
#![feature(conservative_impl_trait)]
@ -17,12 +28,16 @@
extern crate cobs;
#[macro_use]
extern crate error_chain;
extern crate ref_slice;
pub mod channel;
pub mod error;
use error::{Error, ErrorKind, Result};
use std::io::{Read, Write};
use ref_slice::ref_slice_mut;
use std::io::{self, Read, Write};
const FRAME_END: u8 = 0;
/// Sends frames over an underlying `io::Write` instance.
pub struct Sender<W: Write> {
@ -37,7 +52,11 @@ impl<W: Write> Sender<W> {
}
pub fn send(&mut self, f: &[u8]) -> Result<()> {
let code = cobs::encode_vec(f);
let mut code = cobs::encode_vec(f);
code.push(FRAME_END);
#[cfg(feature = "trace")] {
println!("framed: Sending code = {:?}", code);
}
self.w.write(&code)?;
Ok(())
}
@ -45,6 +64,7 @@ impl<W: Write> Sender<W> {
/// Receives frames from an underlying `io::Read` instance.
pub struct Receiver<R: Read> {
/// The underlying reader
r: R,
}
@ -56,9 +76,35 @@ impl<R: Read> Receiver<R> {
}
pub fn recv(&mut self) -> Result<Vec<u8>> {
let mut code = Vec::new();
self.r.read_to_end(&mut code)?;
cobs::decode_vec(&code)
let mut next_frame = Vec::new();
let mut b = 0u8;
loop {
let res = self.r.read(ref_slice_mut(&mut b));
#[cfg(feature = "trace")] {
println!("framed: Read result = {:?}", res);
}
match res {
Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof =>
return Err(Error::from(ErrorKind::EofDuringFrame)),
Ok(0) =>
return Err(Error::from(ErrorKind::EofDuringFrame)),
Err(e) => return Err(Error::from(e)),
Ok(_) => (),
};
#[cfg(feature = "trace")] {
println!("framed: Read byte = {}", b);
}
if b == FRAME_END {
break;
} else {
next_frame.push(b);
}
}
assert!(b == FRAME_END);
cobs::decode_vec(&next_frame)
.map_err(|_| Error::from(ErrorKind::CobsDecodeFailed))
}
}
@ -66,6 +112,7 @@ impl<R: Read> Receiver<R> {
#[cfg(test)]
mod tests {
use channel::Channel;
use error::{Error, ErrorKind};
use std::io::{Read, Write};
use super::{Receiver, Sender};
@ -78,13 +125,50 @@ mod tests {
assert_eq!(recvd, sent);
}
// TODO: Test sending 2 different frames.
#[test]
fn two_frames_sequentially() {
let (mut tx, mut rx) = pair();
{
let sent = [0x00, 0x01, 0x02];
tx.send(&sent).unwrap();
let recvd = rx.recv().unwrap();
assert_eq!(recvd, sent);
}
// TODO: Test buffering:
// * Write half a frame
// * recv() returns nothing
// * Write the rest of the frame
// * recv() returns the whole frame
{
let sent = [0x10, 0x11, 0x12];
tx.send(&sent).unwrap();
let recvd = rx.recv().unwrap();
assert_eq!(recvd, sent);
}
}
#[test]
fn two_frames_at_once() {
let (mut tx, mut rx) = pair();
let s1 = [0x00, 0x01, 0x02];
let s2 = [0x10, 0x11, 0x12];
tx.send(&s1).unwrap();
tx.send(&s2).unwrap();
let r1 = rx.recv().unwrap();
let r2 = rx.recv().unwrap();
println!("r1: {:?}\n\
r2: {:?}", r1, r2);
assert_eq!(r1, s1);
assert_eq!(r2, s2);
}
#[test]
fn empty_input() {
let (mut _tx, mut rx) = pair();
match rx.recv() {
Err(Error(ErrorKind::EofDuringFrame, _)) => (),
e @ _ => panic!("Bad value: {:?}", e)
}
}
fn pair() -> (Sender<impl Write>, Receiver<impl Read>) {
let c = Channel::new();