Added proper tests (but more should be addedgit add --all :/)

This commit is contained in:
Francesco Cogno 2019-05-17 11:00:53 +02:00
parent 792a821de0
commit 70178cb8d6
No known key found for this signature in database
GPG key ID: 20883E192428EA7A

View file

@ -1,4 +1,5 @@
use crate::exporter_error::PeerEntryParseError; use crate::exporter_error::PeerEntryParseError;
use log::debug;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryFrom; use std::convert::TryFrom;
@ -22,82 +23,96 @@ fn after_char(s: &str, c_split: char) -> &str {
s s
} }
fn parse_peer_entry<'a>(lines: &[&'a str]) -> Result<PeerEntry<'a>, PeerEntryParseError> { impl<'a> TryFrom<&[&'a str]> for PeerEntry<'a> {
let mut public_key = ""; type Error = PeerEntryParseError;
let mut allowed_ips = "";
let mut name = None;
for line in lines { fn try_from(lines: &[&'a str]) -> Result<PeerEntry<'a>, Self::Error> {
if line.starts_with("PublicKey") { let mut public_key = "";
public_key = after_char(line, '=').trim(); let mut allowed_ips = "";
} else if line.starts_with("AllowedIPs") { let mut name = None;
allowed_ips = after_char(line, '=').trim();
} else if line.starts_with("#") { for line in lines {
name = Some(line[1..].trim()); if line.starts_with("PublicKey") {
public_key = after_char(line, '=').trim();
} else if line.starts_with("AllowedIPs") {
allowed_ips = after_char(line, '=').trim();
} else if line.starts_with("#") {
// since the pound sign is 1 byte the below slice will work
name = Some(line[1..].trim());
}
} }
}
// Sanity checks // Sanity checks
if public_key == "" { // If there are more than one PublicKey or AllowedIPs we won't catch it. But
let lines_owned: Vec<String> = lines.into_iter().map(|line| line.to_string()).collect(); // WireGuard won't be working either so we can live with this simplification.
Err(PeerEntryParseError::PublicKeyNotFound { lines: lines_owned }) if public_key == "" {
} else if allowed_ips == "" { // we return a owned String for ergonomics. This will allocate but it's ok since it's not supposed
let lines_owned: Vec<String> = lines.into_iter().map(|line| line.to_string()).collect(); // to happen :)
Err(PeerEntryParseError::AllowedIPsEntryNotFound { lines: lines_owned }) let lines_owned: Vec<String> = lines.into_iter().map(|line| line.to_string()).collect();
} else { Err(PeerEntryParseError::PublicKeyNotFound { lines: lines_owned })
Ok(PeerEntry { } else if allowed_ips == "" {
public_key, let lines_owned: Vec<String> = lines.into_iter().map(|line| line.to_string()).collect();
allowed_ips, Err(PeerEntryParseError::AllowedIPsEntryNotFound { lines: lines_owned })
name, // name can be None } else {
}) Ok(PeerEntry {
public_key,
allowed_ips,
name, // name can be None
})
}
} }
} }
pub(crate) fn parse<'a>( #[derive(Debug, Default, Clone)]
txt: &'a str, pub(crate) struct PeerEntryHashMap<'a>(HashMap<&'a str, PeerEntry<'a>>);
) -> Result<HashMap<&'a str, PeerEntry<'a>>, PeerEntryParseError> {
let mut ht = HashMap::new();
let mut v_blocks = Vec::new(); impl<'a> TryFrom<&'a str> for PeerEntryHashMap<'a> {
let mut cur_block: Option<Vec<&str>> = None; type Error = PeerEntryParseError;
for line in txt.lines().into_iter() { fn try_from(txt: &'a str) -> Result<PeerEntryHashMap, Self::Error> {
if line.starts_with("[") { let mut hm = HashMap::new();
if let Some(inner_cur_block) = cur_block {
// close the block
v_blocks.push(inner_cur_block);
cur_block = None;
}
if line == "[Peer]" { let mut v_blocks = Vec::new();
// start a new block let mut cur_block: Option<Vec<&str>> = None;
cur_block = Some(Vec::new());
} for line in txt.lines().into_iter() {
} else { if line.starts_with("[") {
// push the line if we are in a block (only if not empty) if let Some(inner_cur_block) = cur_block {
if let Some(inner_cur_block) = &mut cur_block { // close the block
if line != "" { v_blocks.push(inner_cur_block);
inner_cur_block.push(line); cur_block = None;
}
if line == "[Peer]" {
// start a new block
cur_block = Some(Vec::new());
}
} else {
// push the line if we are in a block (only if not empty)
if let Some(inner_cur_block) = &mut cur_block {
if line != "" {
inner_cur_block.push(line);
}
} }
} }
} }
if let Some(cur_block) = cur_block {
// we have a leftover block
v_blocks.push(cur_block);
}
debug!("v_blocks == {:?}", v_blocks);
for block in &v_blocks {
let p: PeerEntry = PeerEntry::try_from(&block as &[&str])?;
hm.insert(p.public_key, p);
}
debug!("hm == {:?}", hm);
Ok(PeerEntryHashMap(hm))
} }
if let Some(cur_block) = cur_block {
// we have a leftover block
v_blocks.push(cur_block);
}
println!("v_blocks == {:?}", v_blocks);
for block in &v_blocks {
let p = parse_peer_entry(block)?;
ht.insert(p.public_key, p);
}
println!("ht == {:?}", ht);
Ok(ht)
} }
#[cfg(test)] #[cfg(test)]
@ -139,14 +154,69 @@ AllowedIPs = 10.70.0.40/32
# OnePlus 5T # OnePlus 5T
PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk= PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=
AllowedIPs = 10.70.0.80/32 AllowedIPs = 10.70.0.80/32
";
const TEXT_NOPK: &'static str = "
ListenPort = 51820
PrivateKey = my_super_secret_private_key
# PreUp = iptables -t nat -A POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
# PostDown = iptables -t nat -D POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
[Peer]
# OnePlus 6T
PublicKey = 2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=
AllowedIPs = 10.70.0.2/32
[Peer]
# varch.local (laptop)
AllowedIPs = 10.70.0.3/32
[Peer]
# cantarch
PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=
AllowedIPs = 10.70.0.4/32
";
const TEXT_AIP: &'static str = "
ListenPort = 51820
PrivateKey = my_super_secret_private_key
# PreUp = iptables -t nat -A POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
# PostDown = iptables -t nat -D POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
[Peer]
# OnePlus 6T
PublicKey = 2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=
AllowedIPs = 10.70.0.2/32
[Peer]
# varch.local (laptop)
AllowedIPs = 10.70.0.3/32
PublicKey = 6S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=
[Peer]
# cantarch
PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=
"; ";
#[test] #[test]
fn test_parse() { fn test_parse_ok() {
let a = parse(TEXT); let a: PeerEntryHashMap = PeerEntryHashMap::try_from(TEXT).unwrap();
println!("{:?}", a); println!("{:?}", a);
} }
#[test] #[test]
fn test_parse_and_serialize() {} #[should_panic(
expected = "PublicKeyNotFound { lines: [\"# varch.local (laptop)\", \"AllowedIPs = 10.70.0.3/32\"] }"
)]
fn test_parse_no_public_key() {
let _: PeerEntryHashMap = PeerEntryHashMap::try_from(TEXT_NOPK).unwrap();
}
#[test]
#[should_panic(
expected = "AllowedIPsEntryNotFound { lines: [\"# cantarch\", \"PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=\"] }"
)]
fn test_parse_no_allowed_ips() {
let _: PeerEntryHashMap = PeerEntryHashMap::try_from(TEXT_AIP).unwrap();
}
} }