From dbcaa1a1a57f89719dcb57bac08ad521aadd31b9 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sat, 14 Feb 2026 09:11:22 +0100 Subject: [PATCH] more checks and updated pipeines --- .gitea/workflows/traceability-check.yml | 2 +- .gitea/workflows/traceability.yml | 2 +- src-tauri/src/jellyfin/types.rs | 234 ++++++++++++++++++++++++ src-tauri/src/storage/models.rs | 118 ++++++++++++ 4 files changed, 354 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/traceability-check.yml b/.gitea/workflows/traceability-check.yml index 3b9f4d1..36732bc 100644 --- a/.gitea/workflows/traceability-check.yml +++ b/.gitea/workflows/traceability-check.yml @@ -14,7 +14,7 @@ on: jobs: validate-traces: - runs-on: ubuntu-latest + runs-on: [linux, amd64] name: Check Requirement Traces steps: diff --git a/.gitea/workflows/traceability.yml b/.gitea/workflows/traceability.yml index d1a8a0b..161ad2f 100644 --- a/.gitea/workflows/traceability.yml +++ b/.gitea/workflows/traceability.yml @@ -15,7 +15,7 @@ on: jobs: traceability: name: Validate Requirement Traces - runs-on: ubuntu-latest + runs-on: [linux, amd64] steps: - name: Checkout code diff --git a/src-tauri/src/jellyfin/types.rs b/src-tauri/src/jellyfin/types.rs index a730fc0..bd3ef52 100644 --- a/src-tauri/src/jellyfin/types.rs +++ b/src-tauri/src/jellyfin/types.rs @@ -41,3 +41,237 @@ pub struct PlaybackProgressRequest { #[serde(skip_serializing_if = "Option::is_none")] pub play_session_id: Option, } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_jellyfin_config_creation() { + let config = JellyfinConfig { + server_url: "https://jellyfin.example.com".to_string(), + access_token: "token-123".to_string(), + device_id: "device-456".to_string(), + }; + + assert_eq!(config.server_url, "https://jellyfin.example.com"); + assert_eq!(config.access_token, "token-123"); + assert_eq!(config.device_id, "device-456"); + } + + #[test] + fn test_jellyfin_config_clone() { + let config = JellyfinConfig { + server_url: "https://server.local".to_string(), + access_token: "token-abc".to_string(), + device_id: "device-xyz".to_string(), + }; + + let cloned = config.clone(); + assert_eq!(config.server_url, cloned.server_url); + assert_eq!(config.access_token, cloned.access_token); + assert_eq!(config.device_id, cloned.device_id); + } + + #[test] + fn test_playback_start_request_serialization() { + let request = PlaybackStartRequest { + item_id: "item-123".to_string(), + position_ticks: 0, + play_session_id: Some("session-456".to_string()), + play_command: "PlayNow".to_string(), + is_paused: false, + }; + + let json = serde_json::to_string(&request); + assert!(json.is_ok()); + let serialized = json.unwrap(); + assert!(serialized.contains("item-123")); + assert!(serialized.contains("PlayNow")); + } + + #[test] + fn test_playback_start_request_without_session() { + let request = PlaybackStartRequest { + item_id: "item-789".to_string(), + position_ticks: 1_000_000, + play_session_id: None, + play_command: "Resume".to_string(), + is_paused: true, + }; + + let json = serde_json::to_string(&request).unwrap(); + assert!(json.contains("true")); + assert!(!json.contains("playSessionId")); + } + + #[test] + fn test_playback_start_request_pascal_case() { + let request = PlaybackStartRequest { + item_id: "item-1".to_string(), + position_ticks: 100, + play_session_id: Some("session-1".to_string()), + play_command: "Play".to_string(), + is_paused: false, + }; + + let json = serde_json::to_string(&request).unwrap(); + // Verify PascalCase serialization + assert!(json.contains("ItemId")); + assert!(json.contains("PositionTicks")); + assert!(json.contains("PlaySessionId")); + assert!(json.contains("PlayCommand")); + assert!(json.contains("IsPaused")); + } + + #[test] + fn test_playback_stopped_request_serialization() { + let request = PlaybackStoppedRequest { + item_id: "item-555".to_string(), + position_ticks: 5_000_000, + play_session_id: Some("session-789".to_string()), + }; + + let json = serde_json::to_string(&request); + assert!(json.is_ok()); + let serialized = json.unwrap(); + assert!(serialized.contains("item-555")); + assert!(serialized.contains("5000000")); + } + + #[test] + fn test_playback_stopped_request_without_session() { + let request = PlaybackStoppedRequest { + item_id: "item-000".to_string(), + position_ticks: 0, + play_session_id: None, + }; + + let json = serde_json::to_string(&request).unwrap(); + assert!(json.contains("item-000")); + assert!(!json.contains("playSessionId")); + } + + #[test] + fn test_playback_stopped_request_pascal_case() { + let request = PlaybackStoppedRequest { + item_id: "i1".to_string(), + position_ticks: 500, + play_session_id: Some("s1".to_string()), + }; + + let json = serde_json::to_string(&request).unwrap(); + assert!(json.contains("ItemId")); + assert!(json.contains("PositionTicks")); + assert!(json.contains("PlaySessionId")); + } + + #[test] + fn test_playback_progress_request_serialization() { + let request = PlaybackProgressRequest { + item_id: "item-999".to_string(), + position_ticks: 150_000_000, + is_paused: false, + play_session_id: Some("session-111".to_string()), + }; + + let json = serde_json::to_string(&request); + assert!(json.is_ok()); + let serialized = json.unwrap(); + assert!(serialized.contains("item-999")); + assert!(serialized.contains("150000000")); + assert!(serialized.contains("false")); + } + + #[test] + fn test_playback_progress_request_paused() { + let request = PlaybackProgressRequest { + item_id: "item-paused".to_string(), + position_ticks: 75_000_000, + is_paused: true, + play_session_id: None, + }; + + let json = serde_json::to_string(&request).unwrap(); + assert!(json.contains("true")); + assert!(json.contains("item-paused")); + } + + #[test] + fn test_playback_progress_request_pascal_case() { + let request = PlaybackProgressRequest { + item_id: "i2".to_string(), + position_ticks: 200, + is_paused: true, + play_session_id: Some("s2".to_string()), + }; + + let json = serde_json::to_string(&request).unwrap(); + assert!(json.contains("ItemId")); + assert!(json.contains("PositionTicks")); + assert!(json.contains("IsPaused")); + assert!(json.contains("PlaySessionId")); + } + + #[test] + fn test_playback_start_request_various_position_values() { + let positions = vec![0, 1_000_000, 10_000_000, 100_000_000, 1_000_000_000]; + + for pos in positions { + let request = PlaybackStartRequest { + item_id: "item-test".to_string(), + position_ticks: pos, + play_session_id: None, + play_command: "Play".to_string(), + is_paused: false, + }; + + let json = serde_json::to_string(&request).unwrap(); + assert!(json.contains("item-test")); + assert!(json.contains(&pos.to_string())); + } + } + + #[test] + fn test_jellyfin_config_debug() { + let config = JellyfinConfig { + server_url: "https://debug.example.com".to_string(), + access_token: "token-debug".to_string(), + device_id: "device-debug".to_string(), + }; + + let debug_str = format!("{:?}", config); + assert!(debug_str.contains("JellyfinConfig")); + assert!(debug_str.contains("https://debug.example.com")); + } + + #[test] + fn test_playback_requests_creation_patterns() { + // Test various creation patterns + let start = PlaybackStartRequest { + item_id: "i1".to_string(), + position_ticks: 0, + play_session_id: None, + play_command: "PlayNow".to_string(), + is_paused: false, + }; + + let stopped = PlaybackStoppedRequest { + item_id: "i1".to_string(), + position_ticks: 1_000_000, + play_session_id: None, + }; + + let progress = PlaybackProgressRequest { + item_id: "i1".to_string(), + position_ticks: 500_000, + is_paused: false, + play_session_id: None, + }; + + // All should serialize successfully + assert!(serde_json::to_string(&start).is_ok()); + assert!(serde_json::to_string(&stopped).is_ok()); + assert!(serde_json::to_string(&progress).is_ok()); + } +} diff --git a/src-tauri/src/storage/models.rs b/src-tauri/src/storage/models.rs index 7c513fa..10fc5cc 100644 --- a/src-tauri/src/storage/models.rs +++ b/src-tauri/src/storage/models.rs @@ -13,3 +13,121 @@ pub struct PlaylistItem { pub sort_order: i32, pub added_at: Option>, } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_playlist_item_creation() { + let item = PlaylistItem { + id: Some(1), + playlist_id: "playlist-123".to_string(), + item_id: "item-456".to_string(), + sort_order: 0, + added_at: None, + }; + + assert_eq!(item.id, Some(1)); + assert_eq!(item.playlist_id, "playlist-123"); + assert_eq!(item.item_id, "item-456"); + assert_eq!(item.sort_order, 0); + assert!(item.added_at.is_none()); + } + + #[test] + fn test_playlist_item_without_id() { + let item = PlaylistItem { + id: None, + playlist_id: "playlist-789".to_string(), + item_id: "item-999".to_string(), + sort_order: 5, + added_at: None, + }; + + assert!(item.id.is_none()); + assert_eq!(item.sort_order, 5); + } + + #[test] + fn test_playlist_item_serialization() { + let item = PlaylistItem { + id: Some(42), + playlist_id: "pl-001".to_string(), + item_id: "it-001".to_string(), + sort_order: 10, + added_at: None, + }; + + let json = serde_json::to_string(&item); + assert!(json.is_ok()); + let serialized = json.unwrap(); + assert!(serialized.contains("pl-001")); + assert!(serialized.contains("it-001")); + assert!(serialized.contains("10")); + } + + #[test] + fn test_playlist_item_clone() { + let item = PlaylistItem { + id: Some(99), + playlist_id: "clone-playlist".to_string(), + item_id: "clone-item".to_string(), + sort_order: 3, + added_at: None, + }; + + let cloned = item.clone(); + assert_eq!(item.id, cloned.id); + assert_eq!(item.playlist_id, cloned.playlist_id); + assert_eq!(item.item_id, cloned.item_id); + assert_eq!(item.sort_order, cloned.sort_order); + } + + #[test] + fn test_playlist_item_with_timestamp() { + let now = Utc::now(); + let item = PlaylistItem { + id: Some(100), + playlist_id: "time-playlist".to_string(), + item_id: "time-item".to_string(), + sort_order: 7, + added_at: Some(now), + }; + + assert!(item.added_at.is_some()); + assert_eq!(item.added_at, Some(now)); + } + + #[test] + fn test_playlist_item_multiple_sort_orders() { + let sort_orders = vec![0, 1, 5, 10, 100, 999]; + + for order in sort_orders { + let item = PlaylistItem { + id: Some(1), + playlist_id: "pl".to_string(), + item_id: "it".to_string(), + sort_order: order, + added_at: None, + }; + + assert_eq!(item.sort_order, order); + } + } + + #[test] + fn test_playlist_item_debug() { + let item = PlaylistItem { + id: Some(200), + playlist_id: "debug-pl".to_string(), + item_id: "debug-it".to_string(), + sort_order: 15, + added_at: None, + }; + + let debug_str = format!("{:?}", item); + assert!(debug_str.contains("PlaylistItem")); + assert!(debug_str.contains("debug-pl")); + } +}