Skip to content

Commit

Permalink
proptesting
Browse files Browse the repository at this point in the history
  • Loading branch information
edg-l committed Feb 8, 2023
1 parent 7c8b99a commit 4a5c5cd
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 18 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nom_bencode"
version = "0.1.4"
version = "0.2.0"
authors = ["Edgar <[email protected]>"]
description = "A bencode parser written with nom."
repository = "https://github.com/edg-l/nom-bencode/"
Expand Down
9 changes: 5 additions & 4 deletions benches/bencode_bench.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use nom_bencode::*;

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

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

Expand Down
12 changes: 6 additions & 6 deletions src/error.rs → src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use nom::{
error::{ParseError, ErrorKind},
};
//! Errors produced by this library.

use nom::error::{ErrorKind, ParseError};
use std::{fmt::Debug, num::ParseIntError};

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


impl<I> From<BencodeError<I>> for nom::Err<BencodeError<I>> {
fn from(value: BencodeError<I>) -> Self {
match value {
value @ BencodeError::Nom(_, _) => nom::Err::Error(value),
value => nom::Err::Failure(value),
value @ BencodeError::Nom(_, _) => Self::Error(value),
value => Self::Failure(value),
}
}
}
88 changes: 81 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,27 @@
//! }
//! ```

/*
#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![deny(warnings)]
#![deny(clippy::nursery)]
#![deny(clippy::pedantic)]
#![deny(clippy::all)]
*/

use error::BencodeError;
pub use errors::BencodeError;
use nom::{
branch::alt,
bytes::complete::take,
character::complete::{char, digit1},
combinator::{eof, recognize},
multi::{many0, many_till},
sequence::{delimited, pair, preceded},
Err, IResult,
IResult,
};
use std::{collections::HashMap, fmt::Debug};

pub mod error;
pub mod errors;
pub use nom::Err;

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

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

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

prop_compose! {
fn bencode_bytes()(s in vec(any::<u8>(), 1..100)) -> Vec<u8> {
let mut data: Vec<u8> = Vec::with_capacity(s.len() + 5);
data.extend(format!("{}:", s.len()).as_bytes());
data.extend(s);
data
}
}

prop_compose! {
fn bencode_integer()(s in any::<i64>()) -> Vec<u8> {
format!("i{s}e").as_bytes().to_vec()
}
}

prop_compose! {
fn bencode_list()(s in vec((bencode_integer(), bencode_bytes()), 1..100)) -> Vec<u8> {
let mut data: Vec<u8> = Vec::with_capacity(s.len() + 2);
data.extend(b"l");
for (i, (a, b)) in s.iter().enumerate() {
if i % 2 == 0 {
data.extend(a);
data.extend(b);
} else {
data.extend(b);
data.extend(a);
}

}
data.extend(b"e");
data
}
}

prop_compose! {
fn bencode_dict()(s in vec((bencode_bytes(), bencode_bytes()), 1..100)) -> Vec<u8> {
let mut data: Vec<u8> = Vec::with_capacity(s.len() + 2);
data.extend(b"d");
for (i, (a, b)) in s.iter().enumerate() {
if i % 2 == 0 {
data.extend(a);
data.extend(b);
} else {
data.extend(b);
data.extend(a);
}
}
data.extend(b"e");
data
}
}

proptest! {
#[test]
fn doesnt_panic(s in any::<Vec<u8>>()) {
fn proptest_doesnt_panic_or_overflow(s in any::<Vec<u8>>()) {
parse(&s).ok();
}

#[test]
fn proptest_parse_integer(s in bencode_integer()) {
prop_assert!(Value::parse_integer(&s).is_ok());
}

#[test]
fn proptest_parse_bytes(s in bencode_bytes()) {
let mut data: Vec<u8> = Vec::with_capacity(s.len() + 5);
data.extend(format!("{}:", s.len()).as_bytes());
data.extend(s);
prop_assert!(Value::parse_bytes(&data).is_ok());
}

#[test]
fn proptest_parse_list(s in bencode_list()) {
prop_assert!(Value::parse_list(&s).is_ok());
}

#[test]
fn proptest_parse_dict(s in bencode_dict()) {
prop_assert!(Value::parse_dict(&s).is_ok());
}
}
}

0 comments on commit 4a5c5cd

Please sign in to comment.