aboutsummaryrefslogtreecommitdiff
path: root/src/model
diff options
context:
space:
mode:
authorHristo Venev <hristo@venev.name>2019-05-17 19:34:05 +0300
committerHristo Venev <hristo@venev.name>2019-05-18 19:31:47 +0300
commit6b40d416e719bf4811e0f86c9f869328349b8911 (patch)
treee70fab43b169c20648cd2974fdcf0ca52fc8efd0 /src/model
parent86319480498ab424ab1b2079e699530c39e96a61 (diff)
Add tests for IP sets.
Diffstat (limited to 'src/model')
-rw-r--r--src/model/ip.rs191
1 files changed, 155 insertions, 36 deletions
diff --git a/src/model/ip.rs b/src/model/ip.rs
index 4e284de..c20464f 100644
--- a/src/model/ip.rs
+++ b/src/model/ip.rs
@@ -30,6 +30,18 @@ macro_rules! per_proto {
impl $nett {
const BITS: u8 = $bytes * 8;
+ pub fn is_valid(&self) -> bool {
+ let pfx = self.prefix_len;
+ if pfx > Self::BITS {
+ return false;
+ }
+ if pfx == Self::BITS {
+ return true;
+ }
+ let val: $intt = self.address.into();
+ val & ($intt::max_value() >> pfx) == 0
+ }
+
pub fn contains(&self, other: &Self) -> bool {
if self.prefix_len > other.prefix_len {
return false;
@@ -202,6 +214,16 @@ macro_rules! per_proto {
}
}
+ impl<'a> IntoIterator for &'a $sett {
+ type Item = &'a $nett;
+ type IntoIter = std::slice::Iter<'a, $nett>;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.nets.iter()
+ }
+ }
+
impl FromIterator<$nett> for $sett {
#[inline]
fn from_iter<I: IntoIterator<Item = $nett>>(it: I) -> Self {
@@ -294,42 +316,6 @@ macro_rules! per_proto {
per_proto!(Ipv4Net(Ipv4Addr; "IPv4 network"); u32(4); Ipv4Set);
per_proto!(Ipv6Net(Ipv6Addr; "IPv6 network"); u128(16); Ipv6Set);
-impl Ipv4Net {
- pub fn is_valid(self) -> bool {
- let pfx = self.prefix_len;
- if pfx > 32 {
- return false;
- }
- if pfx == 32 {
- return true;
- }
- let val: u32 = self.address.into();
- val & (u32::max_value() >> pfx) == 0
- }
-}
-
-impl Ipv6Net {
- pub fn is_valid(self) -> bool {
- let pfx = self.prefix_len;
- if pfx > 128 {
- return false;
- }
- if pfx == 128 {
- return true;
- }
-
- let val: u128 = self.address.into();
- let val: [u64; 2] = [(val >> 64) as u64, val as u64];
- if pfx >= 64 {
- return val[1] & (u64::max_value() >> (pfx - 64)) == 0;
- }
- if val[1] != 0 {
- return false;
- }
- val[0] & (u64::max_value() >> pfx) == 0
- }
-}
-
fn pfx_split(s: &str) -> Result<(&str, u8), NetParseError> {
let i = if let Some(i) = s.find('/') {
i
@@ -340,3 +326,136 @@ fn pfx_split(s: &str) -> Result<(&str, u8), NetParseError> {
let pfx = u8::from_str(&pfx[1..]).map_err(|_| NetParseError)?;
Ok((addr, pfx))
}
+
+#[cfg(test)]
+mod test {
+ use super::{pfx_split, Ipv4Addr, Ipv4Net, Ipv4Set, Ipv6Addr, Ipv6Net};
+ use std::str::FromStr;
+
+ #[test]
+ fn test_pfx_split() {
+ assert_eq!(pfx_split("asdf/0").unwrap(), ("asdf", 0));
+ assert_eq!(pfx_split("asdf/123").unwrap(), ("asdf", 123));
+ assert_eq!(pfx_split("asdf/0123").unwrap(), ("asdf", 123));
+ assert_eq!(pfx_split("/1").unwrap(), ("", 1));
+ assert_eq!(pfx_split("abc/2").unwrap(), ("abc", 2));
+
+ assert!(pfx_split("no_slash").is_err());
+ assert!(pfx_split("asdf/abc").is_err());
+ assert!(pfx_split("asdf/0abc").is_err());
+ assert!(pfx_split("asdf/0x123").is_err());
+ assert!(pfx_split("asdf/12345").is_err());
+ }
+
+ #[test]
+ fn test_net_parse() {
+ assert_eq!(
+ Ipv4Net::from_str("192.0.2.5/32").unwrap(),
+ Ipv4Net {
+ address: Ipv4Addr::from_str("192.0.2.5").unwrap(),
+ prefix_len: 32,
+ }
+ );
+
+ assert!(Ipv4Net::from_str("error").is_err());
+
+ assert!(Ipv4Net::from_str("192.0.2.128/32").is_ok());
+ assert!(Ipv4Net::from_str("192.0.2.128/25").is_ok());
+ assert!(Ipv4Net::from_str("192.0.2.128/24").is_err());
+ assert!(Ipv4Net::from_str("192.0.2.128").is_err());
+ }
+
+ #[test]
+ fn test_net_display() {
+ assert_eq!(
+ (Ipv4Net {
+ address: Ipv4Addr::from_str("192.0.2.0").unwrap(),
+ prefix_len: 28,
+ })
+ .to_string(),
+ "192.0.2.0/28"
+ );
+
+ assert_eq!(
+ (Ipv6Net {
+ address: Ipv6Addr::from_str("::1").unwrap(),
+ prefix_len: 128,
+ })
+ .to_string(),
+ "::1/128"
+ );
+ }
+
+ fn disp_set(s: &Ipv4Set) -> String {
+ s.iter()
+ .map(Ipv4Net::to_string)
+ .collect::<Vec<_>>()
+ .join(",")
+ }
+
+ #[test]
+ fn test_set_insert() {
+ let mut s = Ipv4Set::default();
+ assert_eq!(disp_set(&s), "");
+
+ s.insert(Ipv4Net::from_str("192.0.2.7/32").unwrap());
+ assert_eq!(disp_set(&s), "192.0.2.7/32");
+
+ s.insert(Ipv4Net::from_str("192.0.2.5/32").unwrap());
+ assert_eq!(disp_set(&s), "192.0.2.5/32,192.0.2.7/32");
+
+ s.insert(Ipv4Net::from_str("192.0.2.6/32").unwrap());
+ assert_eq!(disp_set(&s), "192.0.2.5/32,192.0.2.6/31");
+
+ let mut s1 = s.clone();
+ s1.insert(Ipv4Net::from_str("192.0.2.0/30").unwrap());
+ assert_eq!(disp_set(&s1), "192.0.2.0/30,192.0.2.5/32,192.0.2.6/31");
+
+ s.insert(Ipv4Net::from_str("192.0.2.4/32").unwrap());
+ assert_eq!(disp_set(&s), "192.0.2.4/30");
+
+ s1.insert(Ipv4Net::from_str("192.0.2.4/32").unwrap());
+ assert_eq!(disp_set(&s1), "192.0.2.0/29");
+
+ s.insert(Ipv4Net::from_str("0.0.0.0/0").unwrap());
+ assert_eq!(disp_set(&s), "0.0.0.0/0");
+ }
+
+ #[test]
+ fn test_set_from_slice() {
+ fn s(v: &[&str]) -> String {
+ disp_set(&Ipv4Set::from(
+ v.iter()
+ .cloned()
+ .map(Ipv4Net::from_str)
+ .map(Result::unwrap)
+ .collect::<Vec<_>>(),
+ ))
+ }
+
+ assert_eq!(s(&[]), "");
+ assert_eq!(s(&["192.0.2.7/32"]), "192.0.2.7/32");
+ assert_eq!(s(&["192.0.2.7/32", "192.0.2.7/32"]), "192.0.2.7/32");
+ assert_eq!(
+ s(&["192.0.2.7/32", "192.0.2.5/32"]),
+ "192.0.2.5/32,192.0.2.7/32"
+ );
+ assert_eq!(
+ s(&["192.0.2.7/32", "192.0.2.5/32", "192.0.2.6/32"]),
+ "192.0.2.5/32,192.0.2.6/31"
+ );
+ assert_eq!(
+ s(&[
+ "192.0.2.7/32",
+ "192.0.2.5/32",
+ "192.0.2.6/32",
+ "192.0.2.4/32"
+ ]),
+ "192.0.2.4/30"
+ );
+ assert_eq!(
+ s(&["192.0.2.7/32", "192.0.2.6/32", "192.0.2.5/32", "0.0.0.0/0"]),
+ "0.0.0.0/0"
+ );
+ }
+}