use lorawan_encoding::maccommandcreator::*;
use lorawan_encoding::maccommands::*;
macro_rules! test_helper {
( $data:ident, $name:ident, $type:ident, $size:expr, $( ( $method:ident, $val:expr ) ,)*) => {{
{
assert!($type::new_as_mac_cmd(&[]).is_err());
let mc = $type::new_as_mac_cmd(&$data[..]);
assert!(mc.is_ok());
if let (MacCommand::$name(res), size) = mc.unwrap() {
assert_eq!(size, $size);
$(
assert_eq!(res.$method(), $val);
)*
} else {
panic!("failed to parse {}", stringify!($type));
}
}
}};
( $name:ident, $type:ident ) => {{
{
let data = vec![];
let mc = $type::new_as_mac_cmd(&data[..]);
assert!(mc.is_ok());
if let (MacCommand::$name(_), size) = mc.unwrap() {
assert_eq!(size, 0);
} else {
panic!("failed to parse {}", stringify!($type));
}
}
}};
}
#[test]
fn test_link_check_req_new() {
test_helper!(LinkCheckReq, LinkCheckReqPayload);
}
#[test]
fn test_link_check_ans_new() {
let data = vec![0xa, 0x0f];
test_helper!(
data,
LinkCheckAns,
LinkCheckAnsPayload,
2,
(margin, 10),
(gateway_count, 15),
);
}
#[test]
fn test_link_adr_req_new() {
let data = vec![0x12, 0x04, 0x00, 0x45];
let expected_channel_mask = ChannelMask::new(&[0x04, 0x00]).unwrap();
test_helper!(
data,
LinkADRReq,
LinkADRReqPayload,
4,
(data_rate, 1),
(tx_power, 2),
(channel_mask, expected_channel_mask),
(redundancy, Redundancy::new(0x45)),
);
}
#[test]
fn test_link_adr_ans_new() {
let examples = [
([0x00], false, false, false, false),
([0x01], true, false, false, false),
([0x02], false, true, false, false),
([0x04], false, false, true, false),
([0x07], true, true, true, true),
];
assert!(LinkADRReqPayload::new_as_mac_cmd(&[]).is_err());
for &(ref v, ref e_power, ref e_dr, ref e_cm, ref e_ack) in &examples {
let mc = LinkADRAnsPayload::new_as_mac_cmd(&v[..]);
assert!(mc.is_ok());
if let (MacCommand::LinkADRAns(laa), size) = mc.unwrap() {
assert_eq!(size, 1);
assert_eq!(laa.channel_mask_ack(), *e_power);
assert_eq!(laa.data_rate_ack(), *e_dr);
assert_eq!(laa.powert_ack(), *e_cm);
assert_eq!(laa.ack(), *e_ack);
} else {
panic!("failed to parse LinkADRAnsPayload");
}
}
}
#[test]
fn test_duty_cycle_req_new() {
#![allow(clippy::float_cmp)]
let data = vec![0x02];
test_helper!(
data,
DutyCycleReq,
DutyCycleReqPayload,
1,
(max_duty_cycle_raw, 2),
(max_duty_cycle, 0.25),
);
}
#[test]
fn test_duty_cycle_ans_new() {
test_helper!(DutyCycleAns, DutyCycleAnsPayload);
}
#[test]
fn test_rx_param_setup_req_new() {
let data = vec![0x3b, 0x01, 0x02, 0x04];
test_helper!(
data,
RXParamSetupReq,
RXParamSetupReqPayload,
4,
(dl_settings, DLSettings::new(0x3b)),
(frequency, Frequency::new_from_raw(&data[1..])),
);
}
#[test]
fn test_rx_param_setup_ans_new() {
let examples = [
([0x00], false, false, false, false),
([0x01], true, false, false, false),
([0x02], false, true, false, false),
([0x04], false, false, true, false),
([0x07], true, true, true, true),
];
assert!(RXParamSetupAnsPayload::new_as_mac_cmd(&[]).is_err());
for &(ref v, ref e_ch, ref e_rx2_dr, ref e_rx1_dr_offset, ref e_ack) in &examples {
let mc = RXParamSetupAnsPayload::new_as_mac_cmd(&v[..]);
assert!(mc.is_ok());
if let (MacCommand::RXParamSetupAns(psa), size) = mc.unwrap() {
assert_eq!(size, 1);
assert_eq!(psa.channel_ack(), *e_ch);
assert_eq!(psa.rx2_data_rate_ack(), *e_rx2_dr);
assert_eq!(psa.rx1_dr_offset_ack(), *e_rx1_dr_offset);
assert_eq!(psa.ack(), *e_ack);
} else {
panic!("failed to parse RXParamSetupAnsPayload");
}
}
}
#[test]
fn test_dev_status_req() {
test_helper!(DevStatusReq, DevStatusReqPayload);
}
#[test]
fn test_dev_status_ans() {
let data = vec![0xfe, 0x3f];
test_helper!(
data,
DevStatusAns,
DevStatusAnsPayload,
2,
(battery, 254),
(margin, -1),
);
}
#[test]
fn test_new_channel_req() {
let data = vec![0x03, 0x01, 0x02, 0x04, 0xa5];
test_helper!(
data,
NewChannelReq,
NewChannelReqPayload,
5,
(channel_index, 3),
(frequency, Frequency::new_from_raw(&data[1..4])),
(data_rate_range, DataRateRange::new_from_raw(data[4])),
);
}
#[test]
fn test_new_channel_ans() {
let examples = [
([0x00], false, false, false),
([0x01], true, false, false),
([0x02], false, true, false),
([0x03], true, true, true),
];
assert!(NewChannelAnsPayload::new_as_mac_cmd(&[]).is_err());
for &(ref v, ref e_ch_freq, ref e_drr, ref e_ack) in &examples {
let mc = NewChannelAnsPayload::new_as_mac_cmd(&v[..]);
assert!(mc.is_ok());
if let (MacCommand::NewChannelAns(nca), size) = mc.unwrap() {
assert_eq!(size, 1);
assert_eq!(nca.data_rate_range_ack(), *e_drr);
assert_eq!(nca.channel_freq_ack(), *e_ch_freq);
assert_eq!(nca.ack(), *e_ack);
} else {
panic!("failed to parse RXParamSetupAnsPayload");
}
}
}
#[test]
fn test_rx_timing_setup_req() {
let data = vec![0x02];
test_helper!(
data,
RXTimingSetupReq,
RXTimingSetupReqPayload,
1,
(delay, 2),
);
}
#[test]
fn test_rx_timing_setup_ans() {
test_helper!(RXTimingSetupAns, RXTimingSetupAnsPayload);
}
#[test]
fn test_parse_mac_commands_empty_downlink() {
assert_eq!(parse_mac_commands(&[], false).count(), 0);
}
#[test]
fn test_parse_mac_commands_empty_uplink() {
assert_eq!(parse_mac_commands(&[], true).count(), 0);
}
#[test]
fn test_parse_mac_commands_with_multiple_cmds() {
let data = mac_cmds_payload();
let mut commands = parse_mac_commands(&data[..], true);
assert_eq!(
commands.next(),
Some(MacCommand::LinkCheckReq(LinkCheckReqPayload()))
);
let expected = LinkADRAnsPayload::new_as_mac_cmd(&data[2..]).unwrap().0;
assert_eq!(commands.next(), Some(expected));
}
#[test]
fn test_parse_mac_commands_with_multiple_cmds_with_payloads() {
let data = vec![3, 0, 0, 0, 112, 3, 0, 0, 255, 0];
let mut commands = parse_mac_commands(&data, false);
assert_eq!(
commands.next(),
Some(MacCommand::LinkADRReq(
LinkADRReqPayload::new(&[0, 0, 0, 112]).unwrap()
))
);
assert_eq!(
commands.next(),
Some(MacCommand::LinkADRReq(
LinkADRReqPayload::new(&[0, 0, 255, 0]).unwrap()
))
);
}
fn mac_cmds_payload() -> Vec<u8> {
vec![LinkCheckReqPayload::cid(), LinkADRAnsPayload::cid(), 0x00]
}
#[test]
fn test_dl_settings() {
let dl_settings = DLSettings::new(0x5b);
assert_eq!(dl_settings.rx1_dr_offset(), 0x05);
assert_eq!(dl_settings.rx2_data_rate(), 0x0b);
}
#[test]
fn test_channel_mask() {
let data = vec![0x03, 0x10];
let mut expected = vec![false; 16];
expected[0] = true;
expected[1] = true;
expected[12] = true;
let chan_mask = ChannelMask::new(&data[..]);
assert!(chan_mask.is_ok());
assert_eq!(&chan_mask.unwrap().statuses()[..], &expected[..]);
}
#[test]
fn test_redundancy_channel_mask_control() {
let redundancy = Redundancy::new(0x7f);
assert_eq!(redundancy.channel_mask_control(), 0x07);
}
#[test]
fn test_redundancy_number_of_transmissions() {
let redundancy = Redundancy::new(0x7f);
assert_eq!(redundancy.number_of_transmissions(), 0x0f);
}
#[test]
fn test_frequency_new_bad_payload() {
assert!(Frequency::new(&[]).is_none());
}
#[test]
fn test_frequency_value() {
let data = frequency_payload();
let freq = Frequency::new(&data[..]);
assert!(freq.is_some());
assert_eq!(freq.unwrap().value(), 26_265_700);
}
fn frequency_payload() -> Vec<u8> {
vec![0x01, 0x02, 0x04]
}
#[test]
fn test_data_rate_range() {
let drr_raw = DataRateRange::new(0xa5);
assert!(drr_raw.is_ok());
let drr = drr_raw.unwrap();
assert_eq!(drr.max_data_rate(), 0x0a);
assert_eq!(drr.min_data_range(), 0x05);
}
#[test]
fn test_data_rate_range_inversed_min_and_max() {
let drr = DataRateRange::new(0x5a);
assert!(drr.is_err());
}
#[test]
fn test_data_rate_range_max_equals_min() {
let drr_raw = DataRateRange::new(0x55);
assert!(drr_raw.is_ok());
}
#[test]
fn test_mac_commands_len_with_creators() {
let rx_timing_setup_req = RXTimingSetupReqCreator::new();
let dev_status_req = DevStatusReqCreator::new();
let cmds: Vec<&dyn SerializableMacCommand> = vec![&rx_timing_setup_req, &dev_status_req];
assert_eq!(mac_commands_len(&cmds[..]), 3);
}
#[test]
fn test_mac_commands_len_with_mac_cmds() {
let rx_timing_setup_req = RXTimingSetupReqPayload::new_as_mac_cmd(&[0x02]).unwrap().0;
let dev_status_ans = DevStatusAnsPayload::new_as_mac_cmd(&[0xfe, 0x3f])
.unwrap()
.0;
let cmds: Vec<&dyn SerializableMacCommand> = vec![&rx_timing_setup_req, &dev_status_ans];
assert_eq!(mac_commands_len(&cmds[..]), 5);
}