use std::net::Ipv6Addr;
use bacnet_transport::bip::BipTransport;
use super::*;
fn mac(target: Result<Target, String>) -> Vec<u8> {
match target {
Ok(Target::Mac(mac)) => mac,
Ok(_) => panic!("expected a MAC target"),
Err(e) => panic!("expected a MAC target, got {e}"),
}
}
fn bip6_address(target: Result<Target, String>) -> SocketAddrV6 {
match target {
Ok(Target::Bip6(peer)) => peer,
Ok(_) => panic!("expected a B/IPv6 address target"),
Err(e) => panic!("expected a B/IPv6 address target, got {e}"),
}
}
#[test]
fn test_ip_to_bip_mac() {
let mac = ip_to_bip_mac(Ipv4Addr::new(192, 168, 1, 100), 47808);
assert_eq!(mac, vec![192, 168, 1, 100, 0xBA, 0xC0]);
}
#[test]
fn test_parse_target_ip_no_port() {
assert_eq!(
mac(parse_target("192.168.1.100")),
vec![192, 168, 1, 100, 0xBA, 0xC0]
);
}
#[test]
fn test_parse_target_ip_with_port() {
assert_eq!(
mac(parse_target("10.0.1.100:47809")),
vec![10, 0, 1, 100, 0xBA, 0xC1]
);
}
#[test]
fn test_parse_target_instance() {
let target = parse_target("1234").unwrap();
match target {
Target::Instance(id) => assert_eq!(id, 1234),
_ => panic!("expected Instance target"),
}
}
#[test]
fn test_parse_target_routed() {
let target = parse_target("2:1234").unwrap();
match target {
Target::Routed(dnet, id) => {
assert_eq!(dnet, 2);
assert_eq!(id, 1234);
}
_ => panic!("expected Routed target"),
}
}
#[test]
fn test_parse_target_invalid() {
assert!(parse_target("not-a-target").is_err());
}
#[test]
fn bip6_targets_name_a_vmac() {
assert_eq!(mac(parse_target("bip6:1234")), [0x00, 0x04, 0xD2]);
assert_eq!(mac(parse_target("bip6:0")), [0, 0, 0]);
assert_eq!(mac(parse_target("bip6:4194303")), [0x3F, 0xFF, 0xFF]);
assert_eq!(mac(parse_target("bip6:0x40ABCD")), [0x40, 0xAB, 0xCD]);
assert_eq!(mac(parse_target("bip6:0x40abcd")), [0x40, 0xAB, 0xCD]);
assert_eq!(mac(parse_target("bip6:0X40ABCD")), [0x40, 0xAB, 0xCD]);
}
#[test]
fn bip6_vmac_text_round_trips() {
for vmac in [[0x00, 0x04, 0xD2], [0x40, 0xAB, 0xCD], [0x3F, 0xFF, 0xFF]] {
let printed = crate::output::format_mac(&vmac);
assert_eq!(mac(parse_target(&printed)), vmac, "{printed}");
}
assert_eq!(crate::output::format_mac(&[0, 4, 0xD2]), "bip6:0x0004D2");
}
#[test]
fn bip6_targets_refuse_bad_forms() {
for target in [
"bip6:4194304",
"bip6:4294967295",
"bip6:99999999999999999999",
] {
let error = parse_target(target).err().unwrap();
assert!(
error.contains("must be in 0..=4194303"),
"{target}: {error}"
);
}
for target in [
"bip6:",
"bip6:-1",
"bip6:12a",
"bip6:0x",
"bip6:0x0004D",
"bip6:0x0004D2F",
"bip6:0xGG0000",
] {
let error = parse_target(target).err().unwrap();
assert!(error.contains("bip6:0x<6 hex digits>"), "{target}: {error}");
}
}
#[test]
fn bracketed_ipv6_is_an_address_to_resolve() {
let peer = bip6_address(parse_target("[::1]:47808"));
assert_eq!((*peer.ip(), peer.port()), (Ipv6Addr::LOCALHOST, 47808));
let peer = bip6_address(parse_target("[fe80::1]"));
assert_eq!(peer.ip().segments()[0], 0xfe80);
assert_eq!(peer.port(), 0xBAC0, "the default port");
let peer = bip6_address(parse_target("[fe80::1%3]:47809"));
assert_eq!((peer.scope_id(), peer.port()), (3, 47809));
for target in ["[::1", "[::1]:x", "[nope]:47808", "[::1]47808"] {
let error = parse_target(target).err().unwrap();
assert!(error.contains("[IPv6]:port"), "{target}: {error}");
}
}
#[tokio::test]
async fn a_bip6_address_resolves_to_the_vmac_of_the_node_there() {
let mut server = Bip6Transport::new(Ipv6Addr::LOCALHOST, 0, Some(1234));
let mut client = Bip6Transport::new(Ipv6Addr::LOCALHOST, 0, Some(4321));
let _server_rx = server.start().await.unwrap();
let _client_rx = client.start().await.unwrap();
let server_address = server.local_address().unwrap();
let vmac = bip6_vmac(&client, server_address).await.unwrap();
assert_eq!(vmac, [0x00, 0x04, 0xD2]);
let text = format!("[::1]:{}", server_address.port());
assert_eq!(
address_mac(&client, &text, "unused").await.unwrap(),
[0x00, 0x04, 0xD2]
);
assert_eq!(
address_mac(&client, "bip6:1234", "unused").await.unwrap(),
[0x00, 0x04, 0xD2]
);
assert_eq!(
address_mac(&client, "1234", "needs an address").await,
Err("needs an address".to_string())
);
assert_eq!(
address_mac(&client, "2:1234", "needs an address").await,
Err("needs an address".to_string())
);
client.stop().await.unwrap();
server.stop().await.unwrap();
}
#[tokio::test]
async fn a_bip6_address_needs_the_bip6_transport() {
let bip = BipTransport::new(Ipv4Addr::LOCALHOST, 0, Ipv4Addr::BROADCAST);
let peer = "[::1]:47808".parse().unwrap();
let error = bip6_vmac(&bip, peer).await.unwrap_err();
assert!(error.contains("--ipv6"), "{error}");
assert!(as_bip6(&bip).is_none());
}
#[tokio::test]
async fn a_bip6_vmac_needs_the_bip6_transport() {
let bip = BipTransport::new(Ipv4Addr::LOCALHOST, 0, Ipv4Addr::BROADCAST);
for target in ["bip6:1234", "bip6:0x40ABCD"] {
let error = parse_target_on(&bip, target).err().unwrap();
assert!(
error.contains("bip6: addresses need the --ipv6 transport"),
"{error}"
);
let error = address_mac(&bip, target, "unused").await.unwrap_err();
assert!(error.contains("--ipv6"), "{error}");
}
assert_eq!(
mac(parse_target_on(&bip, "10.0.0.1")),
[10, 0, 0, 1, 0xBA, 0xC0]
);
}