Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
shell: bash

- name: Nightly Test
run: cargo test
run: cargo test --all-features
shell: bash
env:
RUSTFLAGS: '--cfg nightly -Zcrate-attr=feature(variant_count)'
Expand Down
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"rust-analyzer.check.features": [
"arb"
],
"rust-analyzer.cargo.features": [
"arb"
]
}
11 changes: 9 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ version = "0.18.3"

[features]
default = ["url"]
arb = [
"dep:quickcheck",
"dep:rand",
"multihash/arb",
"dep:strum",
]

[dependencies]
arrayref = "0.3"
Expand All @@ -26,11 +32,12 @@ static_assertions = "1.1"
unsigned-varint = "0.8"
url = { version = "2.5.0", optional = true, default-features = false }
libp2p-identity = { version = "0.2.9", features = ["peerid"] }
quickcheck = { version = "1.0.3", default-features = false, optional = true }
rand = {version = "0.9.0", optional = true}
strum = {version = "0.27", features = ["derive"], optional = true}

[dev-dependencies]
bincode = "1"
quickcheck = { version = "1.0.3", default-features = false }
rand = "0.9.0"
serde_json = "1.0"

# Passing arguments to the docsrs builder in order to properly document cfg's.
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ impl Multiaddr {
/// Returns &str identifiers for the protocol names themselves.
/// This omits specific info like addresses, ports, peer IDs, and the like.
/// Example: `"/ip4/127.0.0.1/tcp/5001"` would return `["ip4", "tcp"]`
pub fn protocol_stack(&self) -> ProtoStackIter {
pub fn protocol_stack(&self) -> ProtoStackIter<'_> {
ProtoStackIter { parts: self.iter() }
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/protocol.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#[cfg(feature = "arb")]
mod arb_impl;
#[cfg(feature = "arb")]
pub mod arb_util;

use crate::onion_addr::Onion3Addr;
use crate::{Error, PeerId, Result};
use arrayref::array_ref;
Expand Down Expand Up @@ -84,9 +89,9 @@ const PATH_SEGMENT_ENCODE_SET: &percent_encoding::AsciiSet = &percent_encoding::
///
/// For `Unix`, `Ws` and `Wss` we use `&str` instead of `Path` to allow
/// cross-platform usage of `Protocol` since encoding `Paths` to bytes is
/// platform-specific. This means that the actual validation of paths needs to
/// happen separately.
/// platform-specific. This means that the actual validation of paths needs to happen separately.
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "arb", derive(strum::EnumCount))]
#[non_exhaustive]
pub enum Protocol<'a> {
Dccp(u16),
Expand Down
91 changes: 91 additions & 0 deletions src/protocol/arb_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use std::borrow::Cow;

use crate::{protocol::arb_util::SubString, Multiaddr, Protocol};

impl quickcheck::Arbitrary for Multiaddr {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let iter = (0..u8::arbitrary(g) % 128).map(|_| Protocol::arbitrary(g));
Multiaddr::from_iter(iter)
}
}

impl quickcheck::Arbitrary for Protocol<'static> {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
use quickcheck::Arbitrary;
use std::iter;
use strum::EnumCount;
match usize::arbitrary(g) % Protocol::COUNT {
0 => Protocol::Dccp(Arbitrary::arbitrary(g)),
1 => Protocol::Dns(Cow::Owned(SubString::arbitrary(g).0)),
2 => Protocol::Dns4(Cow::Owned(SubString::arbitrary(g).0)),
3 => Protocol::Dns6(Cow::Owned(SubString::arbitrary(g).0)),
4 => Protocol::Dnsaddr(Cow::Owned(SubString::arbitrary(g).0)),
5 => Protocol::Http,
6 => Protocol::Https,
7 => Protocol::Ip4(std::net::Ipv4Addr::arbitrary(g)),
8 => Protocol::Ip6(std::net::Ipv6Addr::arbitrary(g)),
9 => Protocol::P2pWebRtcDirect,
10 => Protocol::P2pWebRtcStar,
11 => Protocol::WebRTCDirect,
12 => Protocol::Certhash(crate::protocol::Multihash::arbitrary(g)),
13 => Protocol::P2pWebSocketStar,
14 => Protocol::Memory(Arbitrary::arbitrary(g)),
15 => {
let a = iter::repeat_with(|| u8::arbitrary(g))
.take(10)
.collect::<Vec<_>>()
.try_into()
.unwrap();
Protocol::Onion(Cow::Owned(a), std::cmp::max(1, u16::arbitrary(g)))
}
16 => {
let a: [u8; 35] = iter::repeat_with(|| u8::arbitrary(g))
.take(35)
.collect::<Vec<_>>()
.try_into()
.unwrap();
Protocol::Onion3((a, std::cmp::max(1, u16::arbitrary(g))).into())
}
17 => Protocol::P2p(crate::protocol::arb_util::PId::arbitrary(g).0),
18 => Protocol::P2pCircuit,
19 => Protocol::Quic,
20 => Protocol::QuicV1,
21 => Protocol::Sctp(Arbitrary::arbitrary(g)),
22 => Protocol::Tcp(Arbitrary::arbitrary(g)),
23 => Protocol::Tls,
24 => Protocol::Noise,
25 => Protocol::Udp(Arbitrary::arbitrary(g)),
26 => Protocol::Udt,
27 => Protocol::Unix(Cow::Owned(SubString::arbitrary(g).0)),
28 => Protocol::Utp,
29 => Protocol::WebTransport,
30 => Protocol::Ws("/".into()),
31 => Protocol::Wss("/".into()),
32 => Protocol::Ip6zone(Cow::Owned(SubString::arbitrary(g).0)),
33 => Protocol::Ipcidr(Arbitrary::arbitrary(g)),
34 => {
let len = usize::arbitrary(g) % (462 - 387) + 387;
let a = iter::repeat_with(|| u8::arbitrary(g))
.take(len)
.collect::<Vec<_>>();
Protocol::Garlic64(Cow::Owned(a))
}
35 => {
let len = if bool::arbitrary(g) {
32
} else {
usize::arbitrary(g) % 128 + 35
};
let a = iter::repeat_with(|| u8::arbitrary(g))
.take(len)
.collect::<Vec<_>>();
Protocol::Garlic32(Cow::Owned(a))
}
36 => Protocol::Sni(Cow::Owned(SubString::arbitrary(g).0)),
37 => Protocol::P2pStardust,
38 => Protocol::WebRTC,
39 => Protocol::HttpPath(Cow::Owned(SubString::arbitrary(g).0)),
_ => panic!("outside range"),
}
}
}
31 changes: 31 additions & 0 deletions src/protocol/arb_util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//! helper types

use libp2p_identity::PeerId;

/// `PeerId` doesn't `impl quickcheck::Arbitrary` so this newtype is useful beyond this crate for the similar purposes.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct PId(pub PeerId);

impl quickcheck::Arbitrary for PId {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let mut hash: [u8; 32] = [0; 32];
hash.fill_with(|| u8::arbitrary(g));

PId(PeerId::from_multihash(
multihash::Multihash::wrap(0x0, &hash).expect("The digest size is never too large"),
)
.expect("identity multihash works if digest size < 64"))
}
}

/// ASCII string without '/'
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct SubString(pub String);

impl quickcheck::Arbitrary for SubString {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let mut s = String::arbitrary(g);
s.retain(|c| c.is_ascii() && c != '/');
SubString(s)
}
}
Loading