#[cfg(test)]
mod tests {
use crate::call::domain::{MediaCapability, MediaPathMode, MediaRuntimeProfile};
use crate::call::runtime::{AppDescriptor, AppStatus, CapabilityCheckResult};
use serde_json::json;
#[test]
fn ivr_requires_full_capability() {
let desc = AppDescriptor::ivr();
assert!(!desc.required_capabilities.is_empty());
assert!(desc.required_capabilities.contains(&MediaCapability::Full));
}
#[test]
fn signaling_app_works_in_bypass() {
let desc = AppDescriptor::signaling_only();
let bypass_profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Bypass);
let result = desc.check_capabilities(&[bypass_profile.capability]);
assert!(
result.is_satisfied(),
"Signaling-only app should work in bypass mode"
);
}
#[test]
fn ivr_denied_in_bypass() {
let desc = AppDescriptor::ivr();
let bypass_profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Bypass);
let result = desc.check_capabilities(&[bypass_profile.capability]);
assert!(
!result.is_satisfied(),
"IVR should be denied in bypass mode"
);
if let CapabilityCheckResult::Missing(missing) = result {
assert!(missing.contains(&MediaCapability::Full));
} else {
panic!("Expected Missing result");
}
}
#[test]
fn ivr_works_in_anchored() {
let desc = AppDescriptor::ivr();
let anchored_profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Anchored);
let result = desc.check_capabilities(&[anchored_profile.capability]);
assert!(result.is_satisfied(), "IVR should work in anchored mode");
}
#[test]
fn voicemail_requires_full_capability() {
let desc = AppDescriptor::voicemail();
let bypass_profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Bypass);
let result = desc.check_capabilities(&[bypass_profile.capability]);
assert!(
!result.is_satisfied(),
"Voicemail should be denied in bypass mode"
);
let anchored_profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Anchored);
let result = desc.check_capabilities(&[anchored_profile.capability]);
assert!(
result.is_satisfied(),
"Voicemail should work in anchored mode"
);
}
#[test]
fn queue_requires_full_capability() {
let desc = AppDescriptor::queue();
let bypass_profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Bypass);
let result = desc.check_capabilities(&[bypass_profile.capability]);
assert!(
!result.is_satisfied(),
"Queue should be denied in bypass mode"
);
let anchored_profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Anchored);
let result = desc.check_capabilities(&[anchored_profile.capability]);
assert!(result.is_satisfied(), "Queue should work in anchored mode");
}
#[test]
fn dtmf_event_parsing_contract() {
let event = json!({
"type": "dtmf",
"digit": "5"
});
assert!(event.get("type").is_some());
assert_eq!(event.get("type").unwrap(), "dtmf");
assert!(event.get("digit").is_some());
}
#[test]
fn audio_complete_event_contract() {
let event = json!({
"type": "audio_complete",
"track_id": "track-123",
"interrupted": false
});
assert!(event.get("type").is_some());
assert_eq!(event.get("type").unwrap(), "audio_complete");
assert!(event.get("track_id").is_some());
assert!(event.get("interrupted").is_some());
}
#[test]
fn recording_complete_event_contract() {
let event = json!({
"type": "recording_complete",
"path": "/recordings/call-123.wav"
});
assert!(event.get("type").is_some());
assert_eq!(event.get("type").unwrap(), "recording_complete");
assert!(event.get("path").is_some());
}
#[test]
fn custom_event_contract() {
let event = json!({
"type": "custom",
"name": "webhook",
"data": {"action": "transfer", "target": "1001"}
});
assert!(event.get("type").is_some());
assert_eq!(event.get("type").unwrap(), "custom");
assert!(event.get("name").is_some());
if let Some(data) = event.get("data") {
assert!(data.is_object());
}
}
#[test]
fn hangup_event_contract() {
let event = json!({
"type": "hangup",
"reason": "normal_clearing"
});
assert!(event.get("type").is_some());
assert_eq!(event.get("type").unwrap(), "hangup");
}
#[test]
fn timeout_event_contract() {
let event = json!({
"type": "timeout",
"timer_id": "timer-456"
});
assert!(event.get("type").is_some());
assert_eq!(event.get("type").unwrap(), "timeout");
assert!(event.get("timer_id").is_some());
}
#[test]
fn app_status_idle_is_default() {
let status = AppStatus::default();
assert_eq!(status, AppStatus::Idle);
}
#[test]
fn app_status_display_values() {
assert_eq!(AppStatus::Idle.to_string(), "idle");
assert_eq!(AppStatus::Starting.to_string(), "starting");
assert_eq!(AppStatus::Running.to_string(), "running");
assert_eq!(AppStatus::Stopping.to_string(), "stopping");
assert_eq!(AppStatus::Stopped.to_string(), "stopped");
assert_eq!(AppStatus::Failed.to_string(), "failed");
}
#[test]
fn anchored_profile_has_full_capability() {
let profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Anchored);
assert_eq!(profile.capability, MediaCapability::Full);
assert_eq!(profile.path, MediaPathMode::Anchored);
assert!(profile.supports_recording);
assert!(profile.supports_local_ringback);
}
#[test]
fn bypass_profile_has_signaling_only_capability() {
let profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Bypass);
assert_eq!(profile.capability, MediaCapability::SignalingOnly);
assert_eq!(profile.path, MediaPathMode::Bypass);
assert!(!profile.supports_recording);
assert!(!profile.supports_local_ringback);
}
#[test]
fn adaptive_profile_starts_with_limited_capability() {
let profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Adaptive);
assert_eq!(profile.capability, MediaCapability::Limited);
assert_eq!(profile.path, MediaPathMode::Adaptive);
}
#[test]
fn full_satisfies_all_requirements() {
let full = MediaCapability::Full;
let signaling_desc = AppDescriptor::signaling_only();
assert!(signaling_desc.check_capabilities(&[full]).is_satisfied());
let ivr_desc = AppDescriptor::ivr();
assert!(ivr_desc.check_capabilities(&[full]).is_satisfied());
}
#[test]
fn limited_satisfies_limited_and_signaling() {
let limited = MediaCapability::Limited;
let signaling_desc = AppDescriptor::signaling_only();
assert!(signaling_desc.check_capabilities(&[limited]).is_satisfied());
let limited_desc =
AppDescriptor::new("limited_app").with_capabilities(vec![MediaCapability::Limited]);
assert!(limited_desc.check_capabilities(&[limited]).is_satisfied());
let ivr_desc = AppDescriptor::ivr();
assert!(!ivr_desc.check_capabilities(&[limited]).is_satisfied());
}
#[test]
fn signaling_only_satisfies_only_signaling() {
let signaling = MediaCapability::SignalingOnly;
let signaling_desc = AppDescriptor::signaling_only();
let result = signaling_desc.check_capabilities(&[signaling]);
assert!(result.is_satisfied());
let ivr_desc = AppDescriptor::ivr();
assert!(!ivr_desc.check_capabilities(&[signaling]).is_satisfied());
}
#[test]
fn bypass_mode_identifies_unsupported_operations() {
let bypass_profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Bypass);
assert!(!bypass_profile.supports_recording);
assert!(!bypass_profile.supports_local_ringback);
assert!(!bypass_profile.supports_supervisor_media);
assert!(!bypass_profile.supports_media_injection);
}
#[test]
fn anchored_mode_supports_all_operations() {
let anchored_profile = MediaRuntimeProfile::from_media_path(MediaPathMode::Anchored);
assert!(anchored_profile.supports_recording);
assert!(anchored_profile.supports_local_ringback);
assert!(anchored_profile.supports_supervisor_media);
assert!(anchored_profile.supports_media_injection);
}
}