bittorrent_udp: add quickcheck tests for response byte conversion

This commit is contained in:
Joakim Frostegård 2020-04-10 03:30:07 +02:00
parent 46f9a1d13c
commit c964f05e84
5 changed files with 144 additions and 1 deletions

2
Cargo.lock generated
View file

@ -130,6 +130,8 @@ name = "bittorrent_udp"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"quickcheck",
"quickcheck_macros",
] ]
[[package]] [[package]]

View file

@ -6,3 +6,7 @@ edition = "2018"
[dependencies] [dependencies]
byteorder = "1" byteorder = "1"
[dev-dependencies]
quickcheck = "0.9"
quickcheck_macros = "0.9"

View file

@ -185,3 +185,61 @@ pub fn response_from_bytes(
} }
} }
} }
#[cfg(test)]
mod tests {
use quickcheck::{TestResult, quickcheck};
use super::*;
fn same_after_conversion(response: Response, ip_version: IpVersion) -> bool {
let mut buf = Vec::new();
response_to_bytes(&mut buf, response.clone(), ip_version);
let r2 = response_from_bytes(&buf[..], ip_version).unwrap();
let success = response == r2;
if !success {
println!("before: {:#?}\nafter: {:#?}", response, r2);
}
success
}
#[test]
fn test_convert_identity_connect_response(){
fn prop(response: ConnectResponse) -> TestResult {
TestResult::from_bool(same_after_conversion(Response::Connect(response), IpVersion::IPv4))
}
quickcheck(prop as fn(ConnectResponse) -> TestResult);
}
#[test]
fn test_convert_identity_announce_response(){
fn prop(data: (AnnounceResponse, IpVersion)) -> TestResult {
let mut r = data.0;
if data.1 == IpVersion::IPv4 {
r.peers.retain(|peer| peer.ip_address.is_ipv4());
} else {
r.peers.retain(|peer| peer.ip_address.is_ipv6());
}
TestResult::from_bool(same_after_conversion(Response::Announce(r), data.1))
}
quickcheck(prop as fn((AnnounceResponse, IpVersion)) -> TestResult);
}
#[test]
fn test_convert_identity_scrape_response(){
fn prop(response: ScrapeResponse) -> TestResult {
TestResult::from_bool(same_after_conversion(Response::Scrape(response), IpVersion::IPv4))
}
quickcheck(prop as fn(ScrapeResponse) -> TestResult);
}
}

View file

@ -48,3 +48,26 @@ pub struct ResponsePeer {
pub ip_address: net::IpAddr, pub ip_address: net::IpAddr,
pub port: Port, pub port: Port,
} }
#[cfg(test)]
impl quickcheck::Arbitrary for IpVersion {
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
if bool::arbitrary(g) {
IpVersion::IPv4
} else {
IpVersion::IPv6
}
}
}
#[cfg(test)]
impl quickcheck::Arbitrary for ResponsePeer {
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
Self {
ip_address: ::std::net::IpAddr::arbitrary(g),
port: Port(u16::arbitrary(g)),
}
}
}

View file

@ -43,3 +43,59 @@ pub enum Response {
Scrape(ScrapeResponse), Scrape(ScrapeResponse),
Error(ErrorResponse), Error(ErrorResponse),
} }
#[cfg(test)]
impl quickcheck::Arbitrary for TorrentScrapeStatistics {
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
Self {
seeders: NumberOfPeers(i32::arbitrary(g)),
completed: NumberOfDownloads(i32::arbitrary(g)),
leechers: NumberOfPeers(i32::arbitrary(g)),
}
}
}
#[cfg(test)]
impl quickcheck::Arbitrary for ConnectResponse {
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
Self {
connection_id: ConnectionId(i64::arbitrary(g)),
transaction_id: TransactionId(i32::arbitrary(g)),
}
}
}
#[cfg(test)]
impl quickcheck::Arbitrary for AnnounceResponse {
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
let peers = (0..u8::arbitrary(g)).map(|_| {
ResponsePeer::arbitrary(g)
}).collect();
Self {
transaction_id: TransactionId(i32::arbitrary(g)),
announce_interval: AnnounceInterval(i32::arbitrary(g)),
leechers: NumberOfPeers(i32::arbitrary(g)),
seeders: NumberOfPeers(i32::arbitrary(g)),
peers,
}
}
}
#[cfg(test)]
impl quickcheck::Arbitrary for ScrapeResponse {
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
let torrent_stats = (0..u8::arbitrary(g)).map(|_| {
TorrentScrapeStatistics::arbitrary(g)
}).collect();
Self {
transaction_id: TransactionId(i32::arbitrary(g)),
torrent_stats,
}
}
}