use super::*;
use crate::error::AutomotiveError;
use crate::isotp::{AddressMode, IsoTp, IsoTpConfig, IsoTpTiming};
use crate::physical::{mock::MockPhysical, PhysicalLayer};
use crate::types::Frame;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
#[test]
fn test_isotp_single_frame() -> Result<()> {
let mut mock = MockPhysical::new(Some(Box::new(|frame: &Frame| {
Ok(Frame {
id: frame.id,
data: vec![0x01, 0x50], timestamp: 0,
is_extended: false,
is_fd: false,
})
})));
mock.open()?;
let config = IsoTpConfig {
tx_id: 0x123,
rx_id: 0x456,
..Default::default()
};
let mut isotp = IsoTp::with_physical(config, mock);
isotp.open()?;
isotp.send(&[0x10])?;
let response = isotp.receive()?;
assert_eq!(response, vec![0x50]);
Ok(())
}
#[test]
fn test_isotp_multi_frame() {
let mock = MockPhysical::new(Some(Box::new(|_frame: &Frame| {
Ok(Frame {
id: 0x456,
data: vec![0x30, 0x00, 0x00], timestamp: 0,
is_extended: false,
is_fd: false,
})
})));
let mut mock = mock;
mock.open().unwrap();
let config = IsoTpConfig {
tx_id: 0x123,
rx_id: 0x456,
block_size: 0, st_min: 0, timing: IsoTpTiming {
n_as: 1000,
n_ar: 1000,
n_bs: 1000,
n_cr: 1000,
},
..Default::default()
};
let mut isotp = IsoTp::with_physical(config, mock);
isotp.open().unwrap();
let data = vec![0x10; 20];
isotp.send(&data).unwrap();
isotp.close().unwrap();
}
#[test]
fn test_isotp_extended_addressing() -> Result<()> {
let mut mock = MockPhysical::new(Some(Box::new(|frame: &Frame| {
assert_eq!(frame.data[0], 0x55); Ok(Frame {
id: frame.id,
data: vec![0x55, 0x01, 0x50], timestamp: 0,
is_extended: false,
is_fd: false,
})
})));
mock.open()?;
let config = IsoTpConfig {
tx_id: 0x123,
rx_id: 0x456,
address_mode: AddressMode::Extended,
address_extension: 0x55,
..Default::default()
};
let mut isotp = IsoTp::with_physical(config, mock);
isotp.open()?;
isotp.send(&[0x10])?;
let response = isotp.receive()?;
assert_eq!(response, vec![0x50]);
Ok(())
}
#[test]
fn test_isotp_mixed_addressing() -> Result<()> {
let mut mock = MockPhysical::new(Some(Box::new(|frame: &Frame| {
assert_eq!(frame.id & 0xFF, 0x55); Ok(Frame {
id: (frame.id & 0xFFFFFF00) | 0x55, data: vec![0x01, 0x50], timestamp: 0,
is_extended: false,
is_fd: false,
})
})));
mock.open()?;
let config = IsoTpConfig {
tx_id: 0x123,
rx_id: 0x456,
address_mode: AddressMode::Mixed,
address_extension: 0x55,
..Default::default()
};
let mut isotp = IsoTp::with_physical(config, mock);
isotp.open()?;
isotp.send(&[0x10])?;
Ok(())
}
#[test]
fn test_isotp_padding() -> Result<()> {
let mut mock = MockPhysical::new(Some(Box::new(|frame: &Frame| {
assert_eq!(frame.data.len(), 8);
assert_eq!(&frame.data[2..], &[0xAA; 6]);
Ok(Frame {
id: frame.id,
data: vec![0x01, 0x50], timestamp: 0,
is_extended: false,
is_fd: false,
})
})));
mock.open()?;
let config = IsoTpConfig {
tx_id: 0x123,
rx_id: 0x456,
use_padding: true,
padding_value: 0xAA,
..Default::default()
};
let mut isotp = IsoTp::with_physical(config, mock);
isotp.open()?;
isotp.send(&[0x10])?;
let response = isotp.receive()?;
assert_eq!(response, vec![0x50]);
Ok(())
}
#[test]
fn test_isotp_flow_control() {
let mock = MockPhysical::new(Some(Box::new(|_frame: &Frame| {
Ok(Frame {
id: 0x456,
data: vec![0x30, 0x02, 0x10], timestamp: 0,
is_extended: false,
is_fd: false,
})
})));
let mut mock = mock;
mock.open().unwrap();
let config = IsoTpConfig {
tx_id: 0x123,
rx_id: 0x456,
block_size: 0, st_min: 0, timing: IsoTpTiming {
n_as: 1000,
n_ar: 1000,
n_bs: 1000,
n_cr: 1000,
},
..Default::default()
};
let mut isotp = IsoTp::with_physical(config, mock);
isotp.open().unwrap();
let data = vec![0x10; 50];
isotp.send(&data).unwrap();
isotp.close().unwrap();
}
#[test]
fn test_isotp_timeouts() -> Result<()> {
let mut mock = MockPhysical::new(Some(Box::new(|frame: &Frame| {
match frame.data[0] & 0xF0 {
0x10 => {
std::thread::sleep(std::time::Duration::from_millis(100));
Err(AutomotiveError::Timeout)
}
_ => {
std::thread::sleep(std::time::Duration::from_millis(100));
Err(AutomotiveError::Timeout)
}
}
})));
mock.open()?;
let config = IsoTpConfig {
tx_id: 0x123,
rx_id: 0x456,
timing: IsoTpTiming {
n_as: 50, n_ar: 50,
n_bs: 50,
n_cr: 50,
},
..Default::default()
};
let mut isotp = IsoTp::with_physical(config, mock);
isotp.open()?;
let data = vec![0x10; 20]; assert!(matches!(isotp.send(&data), Err(AutomotiveError::Timeout)));
assert!(matches!(isotp.receive(), Err(AutomotiveError::Timeout)));
Ok(())
}
#[test]
fn test_isotp_error_handling() -> Result<()> {
let mut mock = MockPhysical::new(Some(Box::new(|_frame: &Frame| {
Err(AutomotiveError::NotInitialized)
})));
let config = IsoTpConfig {
tx_id: 0x123,
rx_id: 0x456,
timing: IsoTpTiming {
n_as: 50, n_ar: 50,
n_bs: 50,
n_cr: 50,
},
..Default::default()
};
let mut isotp = IsoTp::with_physical(config, mock);
assert!(matches!(
isotp.send(&[0x10]),
Err(AutomotiveError::NotInitialized)
));
assert!(matches!(
isotp.receive(),
Err(AutomotiveError::NotInitialized)
));
Ok(())
}
#[test]
fn test_isotp_invalid_response() {
let mock = MockPhysical::new(Some(Box::new(|_frame: &Frame| {
Ok(Frame {
id: 0,
data: vec![0x7F, 0x00, 0x31], timestamp: 0,
is_extended: false,
is_fd: false,
})
})));
let mut mock = mock;
mock.open().unwrap();
let config = IsoTpConfig {
tx_id: 0x123,
rx_id: 0x456,
..Default::default()
};
let mut isotp = IsoTp::with_physical(config, mock);
isotp.open().unwrap();
let data = vec![0x10; 20]; assert!(matches!(
isotp.send(&data),
Err(AutomotiveError::InvalidParameter)
));
isotp.close().unwrap();
}