Skip to content

Commit 1e8dc9e

Browse files
committed
test a couple of pending points; no benefit to coverage stats though
1 parent d509d7e commit 1e8dc9e

File tree

8 files changed

+155
-121
lines changed

8 files changed

+155
-121
lines changed

NOTES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
### Coverage anomalies
2+
3+
Analysis with the `#[coverage(off)]` attribute in Rust nightly has
4+
revealed that the coverage anomalies are:
5+
6+
- `<Normalize<S, F> as Stream>::poll_next (two regions)`
7+
- `<Filter<S, F> as Stream>::poll_next (two regions)`
8+
- `<RecordStream<S> as Stream>::poll_next (one region)`
9+

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ verified by both `cargo llvm-cov` and codecov.io (badge at top).
9898
The report from `cargo llvm-cov` contains a few exceptions in its summary
9999
data only (5 out of over 3900 regions), but it does not positively
100100
identify any expression in this crate that is not executed by a test.
101-
These anomalies are probably small bits of code from the standard library
101+
These anomalies may be small bits of code from the standard library
102102
that are inlined by the compiler and that are thus out of the control
103103
of this crate.
104104

src/filter/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ where
3333
Poll::Ready(Some(Ok(record)))
3434
}
3535
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
36-
res => res,
36+
Poll::Ready(None) => Poll::Ready(None),
37+
Poll::Pending => Poll::Pending,
3738
}
3839
}
3940
}
@@ -77,7 +78,8 @@ where
7778
}
7879
}
7980
Poll::Ready(Some(Err(e))) => return Poll::Ready(Some(Err(e))),
80-
res => return res,
81+
Poll::Ready(None) => return Poll::Ready(None),
82+
Poll::Pending => return Poll::Pending,
8183
}
8284
}
8385
}

src/filter/test.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,20 @@ async fn normalize_band_no_band() {
127127
assert!(record.get(":band").is_none());
128128
}
129129

130+
#[tokio::test]
131+
async fn trickle_normalize_band() {
132+
let stream =
133+
RecordStream::new("<band:3>20m<eor><band:3>40M<eor>".as_bytes(), true);
134+
let trickled = TrickleStream::new(stream);
135+
let mut normalized = normalize_band(trickled);
136+
137+
let rec = next(&mut normalized).await;
138+
assert_eq!(rec.get(":band").unwrap().as_str(), "20M");
139+
140+
let rec = next(&mut normalized).await;
141+
assert_eq!(rec.get(":band").unwrap().as_str(), "40M");
142+
}
143+
130144
#[tokio::test]
131145
async fn normalize_times_typed() {
132146
let record =
@@ -284,6 +298,20 @@ async fn exclude_callsigns_missing_call() {
284298
assert!(filtered.next().await.is_none());
285299
}
286300

301+
#[tokio::test]
302+
async fn trickle_exclude_callsigns() {
303+
let stream = RecordStream::new(
304+
"<call:4>W1AW<eor><call:5>AB9BH<eor><call:4>W6RQ<eor>".as_bytes(),
305+
true,
306+
);
307+
let trickled = TrickleStream::new(stream);
308+
let mut filtered = exclude_callsigns(trickled, &["W1AW", "W6RQ"]);
309+
310+
let rec = next(&mut filtered).await;
311+
assert_eq!(rec.get("call").unwrap().as_str(), "AB9BH");
312+
assert!(filtered.next().await.is_none());
313+
}
314+
287315
#[tokio::test]
288316
async fn exclude_header_removes_header() {
289317
let stream = RecordStream::new(

src/parse/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,9 +330,8 @@ where
330330
match Pin::new(&mut self.stream).poll_next(cx) {
331331
Poll::Ready(Some(Ok(Tag::Eoh))) => return self.make(true),
332332
Poll::Ready(Some(Ok(Tag::Eor))) => return self.make(false),
333-
Poll::Ready(Some(Ok(Tag::Field(field)))) => {
334-
if let Err(e) = self.record.insert(field.name, field.value)
335-
{
333+
Poll::Ready(Some(Ok(Tag::Field(f)))) => {
334+
if let Err(e) = self.record.insert(f.name, f.value) {
336335
return Poll::Ready(Some(Err(e)));
337336
}
338337
}

src/parse/test.rs

Lines changed: 1 addition & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
2-
use futures::{Stream, StreamExt};
2+
use futures::StreamExt;
33
use rust_decimal::Decimal;
4-
use std::io;
5-
use std::pin::Pin;
64
use std::str::FromStr;
7-
use std::task::{Context, Poll};
8-
use tokio::io::AsyncRead;
95

106
use super::*;
117
use crate::test::helpers::*;
@@ -243,48 +239,6 @@ async fn complete_tag_no_error() {
243239
no_tags(&mut f).await;
244240
}
245241

246-
struct TrickleReader {
247-
data: Vec<u8>,
248-
pos: usize,
249-
chunk: usize,
250-
delayed: bool,
251-
}
252-
253-
impl TrickleReader {
254-
fn new(data: &str, chunk: usize) -> Self {
255-
Self {
256-
data: data.as_bytes().to_vec(),
257-
pos: 0,
258-
chunk,
259-
delayed: false,
260-
}
261-
}
262-
}
263-
264-
impl AsyncRead for TrickleReader {
265-
fn poll_read(
266-
mut self: Pin<&mut Self>, cx: &mut Context<'_>,
267-
buf: &mut tokio::io::ReadBuf<'_>,
268-
) -> Poll<io::Result<()>> {
269-
let remaining = self.data.len() - self.pos;
270-
if remaining == 0 {
271-
return Poll::Ready(Ok(()));
272-
}
273-
274-
if !self.delayed {
275-
self.delayed = true;
276-
cx.waker().wake_by_ref();
277-
return Poll::Pending;
278-
}
279-
280-
let to_read = remaining.min(self.chunk).min(buf.remaining());
281-
buf.put_slice(&self.data[self.pos..self.pos + to_read]);
282-
self.pos += to_read;
283-
self.delayed = false;
284-
Poll::Ready(Ok(()))
285-
}
286-
}
287-
288242
async fn try_trickle_tags(chunk: usize) {
289243
let reader =
290244
TrickleReader::new("Foo <bar:3>baz <qux:5:n>12345 <eoh> ", chunk);
@@ -320,40 +274,6 @@ async fn trickle_invalid() {
320274
assert_eq!(err, invalid_format("foo:3:n", 1, 1, 0));
321275
}
322276

323-
struct TrickleStream<S> {
324-
inner: S,
325-
delayed: bool,
326-
}
327-
328-
impl<S> TrickleStream<S> {
329-
fn new(inner: S) -> Self {
330-
Self {
331-
inner,
332-
delayed: false,
333-
}
334-
}
335-
}
336-
337-
impl<S> Stream for TrickleStream<S>
338-
where
339-
S: Stream + Unpin,
340-
{
341-
type Item = S::Item;
342-
343-
fn poll_next(
344-
mut self: Pin<&mut Self>, cx: &mut Context<'_>,
345-
) -> Poll<Option<Self::Item>> {
346-
if !self.delayed {
347-
self.delayed = true;
348-
cx.waker().wake_by_ref();
349-
return Poll::Pending;
350-
}
351-
352-
self.delayed = false;
353-
Pin::new(&mut self.inner).poll_next(cx)
354-
}
355-
}
356-
357277
#[tokio::test]
358278
async fn trickle_records() {
359279
let reader = TrickleReader::new("<foo:3>abc<eor><foo:4>defg<eor>", 1);

src/test.rs

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,9 @@ use chrono::{NaiveDate, NaiveTime};
44
use rust_decimal::Decimal;
55

66
use super::*;
7-
use helpers::*;
87

9-
pub(crate) mod helpers {
10-
use std::borrow::Cow;
11-
12-
use super::*;
13-
14-
pub(crate) fn invalid_format(
15-
message: &'static str, line: usize, column: usize, byte: usize,
16-
) -> Error {
17-
Error::InvalidFormat {
18-
message: Cow::Borrowed(message),
19-
position: Position { line, column, byte },
20-
}
21-
}
22-
23-
pub(crate) fn partial_data(
24-
line: usize, column: usize, byte: usize,
25-
) -> Error {
26-
invalid_format("partial data at end of stream", line, column, byte)
27-
}
28-
29-
pub(crate) fn duplicate_key(key: &str, record: Record) -> Error {
30-
Error::DuplicateKey {
31-
key: key.to_string(),
32-
record,
33-
}
34-
}
35-
36-
pub(crate) fn cannot_output(
37-
typ: &'static str, reason: &'static str,
38-
) -> Error {
39-
Error::CannotOutput { typ, reason }
40-
}
41-
}
8+
pub(crate) mod helpers;
9+
use helpers::*;
4210

4311
#[test]
4412
fn tag_as_field_returns_some_for_field() {

src/test/helpers.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
use std::borrow::Cow;
2+
use std::io;
3+
use std::pin::Pin;
4+
use std::task::{Context, Poll};
5+
6+
use futures::Stream;
7+
use tokio::io::{AsyncRead, ReadBuf};
8+
9+
use crate::{Error, Position, Record};
10+
11+
pub(crate) fn invalid_format(
12+
message: &'static str, line: usize, column: usize, byte: usize,
13+
) -> Error {
14+
Error::InvalidFormat {
15+
message: Cow::Borrowed(message),
16+
position: Position { line, column, byte },
17+
}
18+
}
19+
20+
pub(crate) fn partial_data(line: usize, column: usize, byte: usize) -> Error {
21+
invalid_format("partial data at end of stream", line, column, byte)
22+
}
23+
24+
pub(crate) fn duplicate_key(key: &str, record: Record) -> Error {
25+
Error::DuplicateKey {
26+
key: key.to_string(),
27+
record,
28+
}
29+
}
30+
31+
pub(crate) fn cannot_output(typ: &'static str, reason: &'static str) -> Error {
32+
Error::CannotOutput { typ, reason }
33+
}
34+
35+
pub(crate) struct TrickleReader {
36+
data: Vec<u8>,
37+
pos: usize,
38+
chunk: usize,
39+
delayed: bool,
40+
}
41+
42+
impl TrickleReader {
43+
pub(crate) fn new(data: &str, chunk: usize) -> Self {
44+
Self {
45+
data: data.as_bytes().to_vec(),
46+
pos: 0,
47+
chunk,
48+
delayed: false,
49+
}
50+
}
51+
}
52+
53+
impl AsyncRead for TrickleReader {
54+
fn poll_read(
55+
mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>,
56+
) -> Poll<io::Result<()>> {
57+
let remaining = self.data.len() - self.pos;
58+
if remaining == 0 {
59+
return Poll::Ready(Ok(()));
60+
}
61+
62+
if !self.delayed {
63+
self.delayed = true;
64+
cx.waker().wake_by_ref();
65+
return Poll::Pending;
66+
}
67+
68+
let to_read = remaining.min(self.chunk).min(buf.remaining());
69+
buf.put_slice(&self.data[self.pos..self.pos + to_read]);
70+
self.pos += to_read;
71+
self.delayed = false;
72+
Poll::Ready(Ok(()))
73+
}
74+
}
75+
76+
pub(crate) struct TrickleStream<S> {
77+
inner: S,
78+
delayed: bool,
79+
}
80+
81+
impl<S> TrickleStream<S> {
82+
pub(crate) fn new(inner: S) -> Self {
83+
Self {
84+
inner,
85+
delayed: false,
86+
}
87+
}
88+
}
89+
90+
impl<S> Stream for TrickleStream<S>
91+
where
92+
S: Stream + Unpin,
93+
{
94+
type Item = S::Item;
95+
96+
fn poll_next(
97+
mut self: Pin<&mut Self>, cx: &mut Context<'_>,
98+
) -> Poll<Option<Self::Item>> {
99+
if !self.delayed {
100+
self.delayed = true;
101+
cx.waker().wake_by_ref();
102+
return Poll::Pending;
103+
}
104+
105+
self.delayed = false;
106+
Pin::new(&mut self.inner).poll_next(cx)
107+
}
108+
}

0 commit comments

Comments
 (0)