use canlink_hal::{BackendConfig, CanBackend, CanId, CanMessage};
use canlink_mock::{MockBackend, MockConfig};
#[test]
fn test_adaptive_message_type() {
let backend_fd = MockBackend::new();
let capability_fd = backend_fd.get_capability().unwrap();
let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let message = if capability_fd.supports_canfd {
CanMessage::new_fd(CanId::Standard(0x123), &data).unwrap()
} else {
CanMessage::new_standard(0x123, &data[..8]).unwrap()
};
assert_eq!(message.data().len(), 12);
let config_20 = MockConfig::can20_only();
let backend_20 = MockBackend::with_config(config_20);
let capability_20 = backend_20.get_capability().unwrap();
let message_20 = if capability_20.supports_canfd {
CanMessage::new_fd(CanId::Standard(0x123), &data).unwrap()
} else {
CanMessage::new_standard(0x123, &data[..8]).unwrap()
};
assert_eq!(message_20.data().len(), 8); }
#[test]
fn test_channel_validation_before_open() {
let mut backend = MockBackend::new();
let config = BackendConfig::new("mock");
backend.initialize(&config).unwrap();
let capability = backend.get_capability().unwrap();
for channel in 0..capability.channel_count {
if capability.has_channel(channel) {
assert!(backend.open_channel(channel).is_ok());
}
}
let invalid_channel = capability.channel_count;
let result = backend.open_channel(invalid_channel);
assert!(result.is_err());
}
#[test]
fn test_bitrate_selection() {
let backend = MockBackend::new();
let capability = backend.get_capability().unwrap();
let preferred_bitrates = [1_000_000, 500_000, 250_000, 125_000];
let selected_bitrate = preferred_bitrates
.iter()
.find(|&&bitrate| capability.supports_bitrate(bitrate))
.copied();
assert_eq!(selected_bitrate, Some(1_000_000));
let mut config = MockConfig::new();
config.supported_bitrates = vec![125_000, 250_000];
let backend_limited = MockBackend::with_config(config);
let capability_limited = backend_limited.get_capability().unwrap();
let selected_limited = preferred_bitrates
.iter()
.find(|&&bitrate| capability_limited.supports_bitrate(bitrate))
.copied();
assert_eq!(selected_limited, Some(250_000));
}
#[test]
fn test_adaptive_data_length() {
fn get_max_data_length(backend: &MockBackend) -> usize {
let capability = backend.get_capability().unwrap();
if capability.supports_canfd {
64 } else {
8 }
}
let backend_fd = MockBackend::new();
assert_eq!(get_max_data_length(&backend_fd), 64);
let config_20 = MockConfig::can20_only();
let backend_20 = MockBackend::with_config(config_20);
assert_eq!(get_max_data_length(&backend_20), 8);
}
#[test]
fn test_multi_channel_adaptation() {
let config_single = MockConfig::can20_only();
let mut backend_single = MockBackend::with_config(config_single);
let config = BackendConfig::new("mock");
backend_single.initialize(&config).unwrap();
let capability_single = backend_single.get_capability().unwrap();
assert_eq!(capability_single.channel_count, 1);
for channel in 0..capability_single.channel_count {
backend_single.open_channel(channel).unwrap();
}
let mut config_multi = MockConfig::new();
config_multi.channel_count = 4;
let mut backend_multi = MockBackend::with_config(config_multi);
backend_multi.initialize(&config).unwrap();
let capability_multi = backend_multi.get_capability().unwrap();
assert_eq!(capability_multi.channel_count, 4);
for channel in 0..capability_multi.channel_count {
backend_multi.open_channel(channel).unwrap();
}
}
#[test]
fn test_timestamp_handling_adaptation() {
fn should_use_timestamps(backend: &MockBackend) -> bool {
let capability = backend.get_capability().unwrap();
capability.timestamp_precision.is_supported()
}
let backend_ts = MockBackend::new();
assert!(should_use_timestamps(&backend_ts));
let mut config_no_ts = MockConfig::new();
config_no_ts.timestamp_precision = canlink_hal::TimestampPrecision::None;
let backend_no_ts = MockBackend::with_config(config_no_ts);
assert!(!should_use_timestamps(&backend_no_ts));
}
#[test]
fn test_filter_allocation() {
fn allocate_filters(backend: &MockBackend, requested: u8) -> u8 {
let capability = backend.get_capability().unwrap();
requested.min(capability.filter_count)
}
let backend_many = MockBackend::new();
assert_eq!(allocate_filters(&backend_many, 20), 16);
let config_few = MockConfig::can20_only();
let backend_few = MockBackend::with_config(config_few);
assert_eq!(allocate_filters(&backend_few, 20), 8); assert_eq!(allocate_filters(&backend_few, 5), 5); }
#[test]
fn test_complete_adaptation_workflow() {
let mut backend = MockBackend::new();
let config = BackendConfig::new("mock");
backend.initialize(&config).unwrap();
let capability = backend.get_capability().unwrap();
let desired_channel = 0;
assert!(capability.has_channel(desired_channel));
backend.open_channel(desired_channel).unwrap();
let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let message = if capability.supports_canfd {
CanMessage::new_fd(CanId::Standard(0x123), &data).unwrap()
} else {
CanMessage::new_standard(0x123, &data[..8]).unwrap()
};
assert!(backend.send_message(&message).is_ok());
let recorded = backend.get_recorded_messages();
assert_eq!(recorded.len(), 1);
assert_eq!(recorded[0].id(), message.id());
}
#[test]
fn test_graceful_degradation() {
let config_20 = MockConfig::can20_only();
let mut backend = MockBackend::with_config(config_20);
let backend_config = BackendConfig::new("mock");
backend.initialize(&backend_config).unwrap();
backend.open_channel(0).unwrap();
let capability = backend.get_capability().unwrap();
let large_data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let message = if capability.supports_canfd {
CanMessage::new_fd(CanId::Standard(0x123), &large_data).unwrap()
} else {
CanMessage::new_standard(0x123, &large_data[..8]).unwrap()
};
assert!(backend.send_message(&message).is_ok());
assert_eq!(message.data().len(), 8); }
#[test]
fn test_capability_feature_flags() {
struct AppConfig {
use_canfd: bool,
use_timestamps: bool,
max_channels: u8,
}
fn create_app_config(backend: &MockBackend) -> AppConfig {
let capability = backend.get_capability().unwrap();
AppConfig {
use_canfd: capability.supports_canfd,
use_timestamps: capability.timestamp_precision.is_supported(),
max_channels: capability.channel_count,
}
}
let backend_fd = MockBackend::new();
let config_fd = create_app_config(&backend_fd);
assert!(config_fd.use_canfd);
assert!(config_fd.use_timestamps);
assert_eq!(config_fd.max_channels, 2);
let mock_config_20 = MockConfig::can20_only();
let backend_20 = MockBackend::with_config(mock_config_20);
let config_20 = create_app_config(&backend_20);
assert!(!config_20.use_canfd);
assert!(config_20.use_timestamps); assert_eq!(config_20.max_channels, 1);
}
#[test]
fn test_runtime_backend_switching() {
let config_20 = MockConfig::can20_only();
let backend_20 = MockBackend::with_config(config_20);
let cap_20 = backend_20.get_capability().unwrap();
assert!(!cap_20.supports_canfd);
let backend_fd = MockBackend::new();
let cap_fd = backend_fd.get_capability().unwrap();
assert!(cap_fd.supports_canfd);
let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let msg_20 = if cap_20.supports_canfd {
CanMessage::new_fd(CanId::Standard(0x123), &data).unwrap()
} else {
CanMessage::new_standard(0x123, &data[..8]).unwrap()
};
assert_eq!(msg_20.data().len(), 8);
let msg_fd = if cap_fd.supports_canfd {
CanMessage::new_fd(CanId::Standard(0x123), &data).unwrap()
} else {
CanMessage::new_standard(0x123, &data[..8]).unwrap()
};
assert_eq!(msg_fd.data().len(), 10);
}