Skip to content

Commit 4a5c5cd

Browse files
committed
proptesting
1 parent 7c8b99a commit 4a5c5cd

File tree

4 files changed

+93
-18
lines changed

4 files changed

+93
-18
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "nom_bencode"
3-
version = "0.1.4"
3+
version = "0.2.0"
44
authors = ["Edgar <git@edgarluque.com>"]
55
description = "A bencode parser written with nom."
66
repository = "https://github.com/edg-l/nom-bencode/"

benches/bencode_bench.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use criterion::{black_box, criterion_group, criterion_main, Criterion};
2+
use nom_bencode::*;
23

3-
static SOURCE_BYTES_22KB: &'static [u8] = include_bytes!("../test-assets/big-buck-bunny.torrent");
4-
static SOURCE_BYTES_113KB: &'static [u8] = include_bytes!("../test-assets/private.torrent");
5-
static SOURCE_BYTES_218KB: &'static [u8] = include_bytes!("../test-assets/multi-file.torrent");
4+
static SOURCE_BYTES_22KB: &[u8] = include_bytes!("../test-assets/big-buck-bunny.torrent");
5+
static SOURCE_BYTES_113KB: &[u8] = include_bytes!("../test-assets/private.torrent");
6+
static SOURCE_BYTES_218KB: &[u8] = include_bytes!("../test-assets/multi-file.torrent");
67

7-
fn parse_source(src: &[u8]) -> Result<Vec<nom_bencode::Value>, nom_bencode::Error<&[u8]>> {
8+
fn parse_source(src: &[u8]) -> Result<Vec<Value>, Err<BencodeError<&[u8]>>> {
89
nom_bencode::parse(src)
910
}
1011

src/error.rs renamed to src/errors.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
use nom::{
2-
error::{ParseError, ErrorKind},
3-
};
1+
//! Errors produced by this library.
2+
3+
use nom::error::{ErrorKind, ParseError};
44
use std::{fmt::Debug, num::ParseIntError};
55

66
/// Parser Errors.
77
#[derive(Debug, thiserror::Error)]
88
pub enum BencodeError<I> {
9+
/// A error from a nom parser.
910
#[error("a nom error: {1:?}")]
1011
Nom(I, ErrorKind),
1112
/// A integer has an invalid form, e.g -0.
@@ -29,12 +30,11 @@ impl<I> ParseError<I> for BencodeError<I> {
2930
}
3031
}
3132

32-
3333
impl<I> From<BencodeError<I>> for nom::Err<BencodeError<I>> {
3434
fn from(value: BencodeError<I>) -> Self {
3535
match value {
36-
value @ BencodeError::Nom(_, _) => nom::Err::Error(value),
37-
value => nom::Err::Failure(value),
36+
value @ BencodeError::Nom(_, _) => Self::Error(value),
37+
value => Self::Failure(value),
3838
}
3939
}
4040
}

src/lib.rs

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,28 +25,27 @@
2525
//! }
2626
//! ```
2727
28-
/*
2928
#![forbid(unsafe_code)]
3029
#![deny(missing_docs)]
3130
#![deny(warnings)]
3231
#![deny(clippy::nursery)]
3332
#![deny(clippy::pedantic)]
3433
#![deny(clippy::all)]
35-
*/
3634

37-
use error::BencodeError;
35+
pub use errors::BencodeError;
3836
use nom::{
3937
branch::alt,
4038
bytes::complete::take,
4139
character::complete::{char, digit1},
4240
combinator::{eof, recognize},
4341
multi::{many0, many_till},
4442
sequence::{delimited, pair, preceded},
45-
Err, IResult,
43+
IResult,
4644
};
4745
use std::{collections::HashMap, fmt::Debug};
4846

49-
pub mod error;
47+
pub mod errors;
48+
pub use nom::Err;
5049

5150
type BenResult<'a> = IResult<&'a [u8], Value<'a>, BencodeError<&'a [u8]>>;
5251

@@ -179,7 +178,7 @@ pub fn parse(source: &[u8]) -> Result<Vec<Value>, Err<BencodeError<&[u8]>>> {
179178
mod tests {
180179
use crate::{parse, BencodeError, Value};
181180
use assert_matches::assert_matches;
182-
use proptest::prelude::*;
181+
use proptest::{collection::vec, prelude::*};
183182

184183
#[test]
185184
fn test_integer() {
@@ -379,10 +378,85 @@ mod tests {
379378
let _ = parse(include_bytes!("../test-assets/multi-file.torrent")).unwrap();
380379
}
381380

381+
prop_compose! {
382+
fn bencode_bytes()(s in vec(any::<u8>(), 1..100)) -> Vec<u8> {
383+
let mut data: Vec<u8> = Vec::with_capacity(s.len() + 5);
384+
data.extend(format!("{}:", s.len()).as_bytes());
385+
data.extend(s);
386+
data
387+
}
388+
}
389+
390+
prop_compose! {
391+
fn bencode_integer()(s in any::<i64>()) -> Vec<u8> {
392+
format!("i{s}e").as_bytes().to_vec()
393+
}
394+
}
395+
396+
prop_compose! {
397+
fn bencode_list()(s in vec((bencode_integer(), bencode_bytes()), 1..100)) -> Vec<u8> {
398+
let mut data: Vec<u8> = Vec::with_capacity(s.len() + 2);
399+
data.extend(b"l");
400+
for (i, (a, b)) in s.iter().enumerate() {
401+
if i % 2 == 0 {
402+
data.extend(a);
403+
data.extend(b);
404+
} else {
405+
data.extend(b);
406+
data.extend(a);
407+
}
408+
409+
}
410+
data.extend(b"e");
411+
data
412+
}
413+
}
414+
415+
prop_compose! {
416+
fn bencode_dict()(s in vec((bencode_bytes(), bencode_bytes()), 1..100)) -> Vec<u8> {
417+
let mut data: Vec<u8> = Vec::with_capacity(s.len() + 2);
418+
data.extend(b"d");
419+
for (i, (a, b)) in s.iter().enumerate() {
420+
if i % 2 == 0 {
421+
data.extend(a);
422+
data.extend(b);
423+
} else {
424+
data.extend(b);
425+
data.extend(a);
426+
}
427+
}
428+
data.extend(b"e");
429+
data
430+
}
431+
}
432+
382433
proptest! {
383434
#[test]
384-
fn doesnt_panic(s in any::<Vec<u8>>()) {
435+
fn proptest_doesnt_panic_or_overflow(s in any::<Vec<u8>>()) {
385436
parse(&s).ok();
386437
}
438+
439+
#[test]
440+
fn proptest_parse_integer(s in bencode_integer()) {
441+
prop_assert!(Value::parse_integer(&s).is_ok());
442+
}
443+
444+
#[test]
445+
fn proptest_parse_bytes(s in bencode_bytes()) {
446+
let mut data: Vec<u8> = Vec::with_capacity(s.len() + 5);
447+
data.extend(format!("{}:", s.len()).as_bytes());
448+
data.extend(s);
449+
prop_assert!(Value::parse_bytes(&data).is_ok());
450+
}
451+
452+
#[test]
453+
fn proptest_parse_list(s in bencode_list()) {
454+
prop_assert!(Value::parse_list(&s).is_ok());
455+
}
456+
457+
#[test]
458+
fn proptest_parse_dict(s in bencode_dict()) {
459+
prop_assert!(Value::parse_dict(&s).is_ok());
460+
}
387461
}
388462
}

0 commit comments

Comments
 (0)