From 360c75dae759514dc64ba8737c2283fef2f76df2 Mon Sep 17 00:00:00 2001 From: euzu <33094714+euzu@users.noreply.github.com> Date: Sun, 1 Feb 2026 14:45:33 +0100 Subject: [PATCH] Feature/fix tests (#561) fixed some tests --- backend/src/library/metadata_resolver.rs | 10 ++- backend/src/library/metadata_storage.rs | 2 +- backend/src/library/nfo_reader.rs | 6 +- backend/src/messaging.rs | 29 ++++---- backend/src/processing/parser/xmltv.rs | 14 ++-- backend/src/processing/parser/xtream.rs | 16 ++--- backend/src/processing/processor/sort.rs | 16 ++--- backend/src/repository/bplustree.rs | 72 +++++++++---------- backend/src/repository/bplustree_stress.rs | 54 ++++++++------ backend/src/repository/sorted_index.rs | 6 +- backend/src/utils/epg_parser.rs | 34 ++++----- .../components/playlist/assistant/playlist.rs | 3 +- .../assistant/playlist_assistant_context.rs | 3 +- shared/src/foundation/filter.rs | 6 +- 14 files changed, 140 insertions(+), 131 deletions(-) diff --git a/backend/src/library/metadata_resolver.rs b/backend/src/library/metadata_resolver.rs index 3c45213c9..692733072 100644 --- a/backend/src/library/metadata_resolver.rs +++ b/backend/src/library/metadata_resolver.rs @@ -166,8 +166,8 @@ mod tests { fn create_test_file(name: &str) -> ScannedMediaFile { ScannedMediaFile { - path: PathBuf::from(format!("/test/{}", name)), - file_path: format!("/test/{}", name), + path: PathBuf::from(format!("/test/{name}")), + file_path: format!("/test/{name}"), file_name: name.to_string(), extension: "mkv".to_string(), size_bytes: 1024, @@ -186,8 +186,7 @@ mod tests { let resolver = MetadataResolver::from_config(&config, client, MetadataStorage::new(PathBuf::from("/tmp"))); let file = create_test_file("The.Matrix.1999.1080p.mkv"); let metadata = match MediaClassifier::classify(&file) { - MediaClassification::Movie { metadata, .. } => metadata, - MediaClassification::Series { metadata, .. } => metadata, + MediaClassification::Movie { metadata, .. } | MediaClassification::Series { metadata, .. } => metadata, }; let group = MediaGroup::Movie { file, metadata: Box::new(metadata) }; @@ -215,8 +214,7 @@ mod tests { let resolver = MetadataResolver::from_config(&config, client, MetadataStorage::new(PathBuf::from("/tmp"))); let file = create_test_file("343jfkjh4789dkjfh934z3.Movie.mkv"); let metadata = match MediaClassifier::classify(&file) { - MediaClassification::Movie { metadata, .. } => metadata, - MediaClassification::Series { metadata, .. } => metadata, + MediaClassification::Movie { metadata, .. } | MediaClassification::Series { metadata, .. } => metadata, }; let group = MediaGroup::Movie { file, metadata: Box::new(metadata) }; diff --git a/backend/src/library/metadata_storage.rs b/backend/src/library/metadata_storage.rs index cb074c1fd..7191b7caa 100644 --- a/backend/src/library/metadata_storage.rs +++ b/backend/src/library/metadata_storage.rs @@ -311,7 +311,7 @@ mod tests { let entry = MetadataCacheEntry::new( "/test/movie.mp4".to_string(), 1024, - 1234567890, + 1_234_567_890, MediaMetadata::Movie(MovieMetadata { title: "Test Movie".to_string(), year: Some(2020), diff --git a/backend/src/library/nfo_reader.rs b/backend/src/library/nfo_reader.rs index bff821283..ee9f788a1 100644 --- a/backend/src/library/nfo_reader.rs +++ b/backend/src/library/nfo_reader.rs @@ -281,8 +281,8 @@ mod tests { assert_eq!(movie.year, Some(1999)); assert_eq!(movie.imdb_id, Some("tt0133093".to_string())); assert_eq!(movie.tmdb_id, Some(603)); - assert_eq!(movie.genres.as_ref().map(|g| g.len()).unwrap_or_default(), 2); - assert_eq!(movie.directors.as_ref().map(|g| g.len()).unwrap_or_default(), 2); + assert_eq!(movie.genres.as_ref().map(Vec::len).unwrap_or_default(), 2); + assert_eq!(movie.directors.as_ref().map(Vec::len).unwrap_or_default(), 2); } else { panic!("Expected movie metadata"); } @@ -316,7 +316,7 @@ mod tests { assert_eq!(series.imdb_id, Some("tt0903747".to_string())); assert_eq!(series.tmdb_id, Some(1396)); assert_eq!(series.tvdb_id, Some(81189)); - assert_eq!(series.genres.as_ref().map(|g| g.len()).unwrap_or_default(), 3); + assert_eq!(series.genres.as_ref().map(Vec::len).unwrap_or_default(), 3); assert_eq!(series.status, Some("Ended".to_string())); } else { panic!("Expected series metadata"); diff --git a/backend/src/messaging.rs b/backend/src/messaging.rs index 6aee0126a..096c83c69 100644 --- a/backend/src/messaging.rs +++ b/backend/src/messaging.rs @@ -281,28 +281,29 @@ async fn resolve_template<'a>(app_config: &'a Arc, http_client: &'a r #[cfg(test)] mod tests { - use arc_swap::ArcSwap; + use arc_swap::{ArcSwap, ArcSwapOption}; use crate::model::ProcessingStats; use super::*; use shared::model::{ConfigPaths}; + use crate::utils::FileLockManager; fn create_app_config() -> Arc { Arc::new(AppConfig { - config: Arc::new(Default::default()), - sources: Arc::new(Default::default()), - hdhomerun: Arc::new(Default::default()), - api_proxy: Arc::new(Default::default()), - file_locks: Arc::new(Default::default()), + config: Arc::new(ArcSwap::default()), + sources: Arc::new(ArcSwap::default()), + hdhomerun: Arc::new(ArcSwapOption::default()), + api_proxy: Arc::new(ArcSwapOption::default()), + file_locks: Arc::new(FileLockManager::default()), paths: Arc::new(ArcSwap::from_pointee(ConfigPaths { - config_path: "".to_string(), - config_file_path: "".to_string(), - sources_file_path: "".to_string(), + config_path: String::new(), + config_file_path: String::new(), + sources_file_path: String::new(), mapping_file_path: None, mapping_files_used: None, - api_proxy_file_path: "".to_string(), + api_proxy_file_path: String::new(), custom_stream_response_path: None, })), - custom_stream_response: Arc::new(Default::default()), + custom_stream_response: Arc::new(ArcSwapOption::default()), access_token_secret: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32], encrypt_secret: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], }) @@ -459,7 +460,7 @@ mod tests { let app_cfg = create_app_config(); let client = reqwest::Client::new(); - let template = r#" + let template = r" *🔄 Playlist Update Report* {{#each stats}} @@ -484,10 +485,10 @@ mod tests { {{/if}} _Timestamp: {{timestamp}}_ - "#; + "; let output = render_template(&app_cfg, &client, Some(template), &content).await; - println!("Telegram Output:\n{}", output); + println!("Telegram Output:\n{output}"); assert!(output.contains("🔄 Playlist Update Report")); assert!(output.contains("Telegram Input")); diff --git a/backend/src/processing/parser/xmltv.rs b/backend/src/processing/parser/xmltv.rs index 33771dbd0..2e0100882 100644 --- a/backend/src/processing/parser/xmltv.rs +++ b/backend/src/processing/parser/xmltv.rs @@ -617,7 +617,6 @@ mod tests { use crate::model::{EpgSmartMatchConfig, PersistedEpgSource, TVGuide}; use crate::processing::parser::xmltv::normalize_channel_name; use std::collections::HashSet; - use std::io; use std::path::PathBuf; #[test] @@ -636,9 +635,9 @@ mod tests { } - #[ignore] + #[ignore = "requires a local XMLTV fixture under /tmp"] #[test] - fn parse_test() -> io::Result<()> { + fn parse_test() { let run_test = async move || { //let file_path = PathBuf::from("/tmp/epg.xml.gz"); let file_path = PathBuf::from("/tmp/invalid_epg.xml"); @@ -652,19 +651,18 @@ mod tests { let channel_ids = HashSet::from([342u32.intern()]); match tv_guide.filter(&mut id_cache).await { - None => assert!(false, "No epg filtered"), + None => panic!("No epg filtered"), Some(epgs) => { for epg in epgs { - assert_eq!(epg.children.len(), channel_ids.len() * 2, "Epg size does not match") + assert_eq!(epg.children.len(), channel_ids.len() * 2, "Epg size does not match"); } } } } }; - let _result = tokio::runtime::Runtime::new() + tokio::runtime::Runtime::new() .unwrap() .block_on(run_test()); - Ok(()) } #[test] @@ -725,4 +723,4 @@ mod tests { println!("{}", metaphone.encode(&normalize_channel_name("BU | ODISEA ᵁᴴᴰ ³⁸⁴⁰ᴾ", &epg_smart_cfg))); println!("{}", metaphone.encode(&normalize_channel_name("BG | ODISEA ᵁᴴᴰ ³⁸⁴⁰ᴾ", &epg_smart_cfg))); } -} \ No newline at end of file +} diff --git a/backend/src/processing/parser/xtream.rs b/backend/src/processing/parser/xtream.rs index 09dc6fc4b..4fa054225 100644 --- a/backend/src/processing/parser/xtream.rs +++ b/backend/src/processing/parser/xtream.rs @@ -387,11 +387,10 @@ mod tests { let file_content = fs::read_to_string("/tmp/series-info.json").expect("Unable to read file"); match serde_json::from_str::(&file_content) { Ok(series_info) => { - println!("{:#?}", series_info); - assert!(true); + println!("{series_info:#?}"); } Err(err) => { - assert!(false, "Failed to parse json file: {err}"); + panic!("Failed to parse json file: {err}"); } } } @@ -402,14 +401,13 @@ mod tests { if fs::exists("/tmp/vod_streams.json").unwrap_or(false) { let reader = Box::pin(async_file_reader(tokio::fs::File::open("/tmp/vod_streams.json").await?)); match map_to_xtream_streams(XtreamCluster::Video, reader, &"test".intern()).await { - Ok(_streams) => { - println!("{:?}", _streams.get(1)); - println!("{:?}", _streams.get(100)); - println!("{:?}", _streams.get(200)); - assert!(true); + Ok(streams) => { + println!("{:?}", streams.get(1)); + println!("{:?}", streams.get(100)); + println!("{:?}", streams.get(200)); } Err(err) => { - assert!(false, "Failed to parse json file: {err}"); + panic!("Failed to parse json file: {err}"); } }; } diff --git a/backend/src/processing/processor/sort.rs b/backend/src/processing/processor/sort.rs index 212772e90..09df463aa 100644 --- a/backend/src/processing/processor/sort.rs +++ b/backend/src/processing/processor/sort.rs @@ -288,7 +288,7 @@ mod tests { .map(|(i, (name, quality))| PlaylistItem { header: PlaylistItemHeader { title: format!("Chanel {name} [{quality}]").into(), - source_ordinal: i as u32, + source_ordinal: u32::try_from(i).unwrap(), ..Default::default() }, }) @@ -313,10 +313,10 @@ mod tests { let ord = playlist_comparator(channel_sort.sequence.as_ref(), channel_sort.order, va, vb); - if ord != Ordering::Equal { - ord - } else { + if ord == Ordering::Equal { a.header.source_ordinal.cmp(&b.header.source_ordinal) + } else { + ord } }); @@ -376,7 +376,7 @@ mod tests { .map(|(i, name)| PlaylistItem { header: PlaylistItemHeader { title: name.to_string().into(), - source_ordinal: i as u32, + source_ordinal: u32::try_from(i).unwrap(), ..Default::default() }, }) @@ -407,10 +407,10 @@ mod tests { &b.header.title, ); - if ord != Ordering::Equal { - ord - } else { + if ord == Ordering::Equal { a.header.source_ordinal.cmp(&b.header.source_ordinal) + } else { + ord } }); diff --git a/backend/src/repository/bplustree.rs b/backend/src/repository/bplustree.rs index 2149aac79..800a3ed5c 100644 --- a/backend/src/repository/bplustree.rs +++ b/backend/src/repository/bplustree.rs @@ -4146,7 +4146,7 @@ mod tests { id: record.id, data: format!("{content} {}", record.id + 9000), }; - tree_update.update(&i, new_record).map_err(|e| e.to_io())?; + tree_update.update(&i, new_record).map_err(BPlusTreeError::to_io)?; } else { panic!("{content} {i} not found"); } @@ -4256,7 +4256,7 @@ mod tests { assert_eq!(update.len().expect("Update len failed"), test_size as usize); // Update existing key - length should stay same - update.update(&1, Record { id: 1, data: "updated".to_string() }).map_err(|e| e.to_io())?; + update.update(&1, Record { id: 1, data: "updated".to_string() }).map_err(BPlusTreeError::to_io)?; assert_eq!(update.len().expect("Update len failed after update"), test_size as usize); // Insert new key - length should increase @@ -4313,7 +4313,7 @@ mod tests { let mut tree_update = BPlusTreeUpdate::::try_new(&filepath)?; for i in 0u32..100 { if i % 2 == 0 { - tree_update.update(&i, Record { id: i, data: format!("UpdatedContent {i}") }).map_err(|e| e.to_io())?; + tree_update.update(&i, Record { id: i, data: format!("UpdatedContent {i}") }).map_err(BPlusTreeError::to_io)?; } } @@ -4357,7 +4357,7 @@ mod tests { let padding: String = generate_random_string(400); for i in 0u32..10 { // Each record has unique data to prevent compression - tree.insert(i, Record { id: i, data: format!("{}{}", padding, i) }); + tree.insert(i, Record { id: i, data: format!("{padding}{i}") }); } tree.store(&filepath)?; @@ -4367,7 +4367,7 @@ mod tests { let mut tree_update = BPlusTreeUpdate::::try_new(&filepath)?; let same_size_padding: String = generate_random_string(400); for i in 0u32..10 { - tree_update.update(&i, Record { id: i, data: format!("{}{}", same_size_padding, i) }).map_err(|e| e.to_io())?; + tree_update.update(&i, Record { id: i, data: format!("{same_size_padding}{i}") }).map_err(BPlusTreeError::to_io)?; } let size_after_same_update = std::fs::metadata(&filepath)?.len(); @@ -4388,7 +4388,7 @@ mod tests { let mut tree_update = BPlusTreeUpdate::::try_new(&filepath)?; let smaller_padding: String = generate_random_string(200); for i in 0u32..10 { - tree_update.update(&i, Record { id: i, data: format!("{}{}", smaller_padding, i) }).map_err(|e| e.to_io())?; + tree_update.update(&i, Record { id: i, data: format!("{smaller_padding}{i}") }).map_err(BPlusTreeError::to_io)?; } let size_after_smaller_update = std::fs::metadata(&filepath)?.len(); @@ -4398,7 +4398,7 @@ mod tests { // 5000 chars is much larger than the original ~400 byte allocation let larger_padding: String = generate_random_string(5000); for i in 0u32..1 { - tree_update.update(&i, Record { id: i, data: format!("{}{}", larger_padding, i) }).map_err(|e| e.to_io())?; + tree_update.update(&i, Record { id: i, data: format!("{larger_padding}{i}") }).map_err(BPlusTreeError::to_io)?; } let size_after_larger_update = std::fs::metadata(&filepath)?.len(); @@ -4444,7 +4444,7 @@ mod tests { // 2. Multiple Updates (COW) for i in (0..test_size).step_by(10) { - tree_update.update(&i, Record { id: i, data: format!("UpdatedContent {i}") }).map_err(|e| e.to_io())?; + tree_update.update(&i, Record { id: i, data: format!("UpdatedContent {i}") }).map_err(BPlusTreeError::to_io)?; } // 3. Verify Query Integrity (Must return NEW values) @@ -4497,7 +4497,7 @@ mod tests { assert_eq!(tree_update.query_le(&5).unwrap().unwrap().id, 0); // 2. COW Update - tree_update.update(&10, Record { id: 10, data: "NewVal".to_string() }).map_err(|e| e.to_io())?; + tree_update.update(&10, Record { id: 10, data: "NewVal".to_string() }).map_err(BPlusTreeError::to_io)?; // 3. Verify LE returns the LATEST value let val = tree_update.query_le(&15).expect("Query failed").expect("Should find LE key after COW update"); @@ -4574,7 +4574,7 @@ mod tests { .map(|(k, v)| (k, v)) .collect(); - tree_update.update_batch(&update_refs).map_err(|e| e.to_io())?; + tree_update.update_batch(&update_refs).map_err(BPlusTreeError::to_io)?; drop(tree_update); // Verify all updates @@ -4612,7 +4612,7 @@ mod tests { // Test empty batch - should be no-op let empty_batch: Vec<(&u32, &Record)> = vec![]; - let result = tree_update.update_batch(&empty_batch).map_err(|e| e.to_io())?; + let result = tree_update.update_batch(&empty_batch).map_err(BPlusTreeError::to_io)?; assert_eq!(result, initial_root, "Empty batch should not change root offset"); @@ -4656,7 +4656,7 @@ mod tests { .collect(); // Perform batch update - tree_update.update_batch(&update_refs).map_err(|e| e.to_io())?; + tree_update.update_batch(&update_refs).map_err(BPlusTreeError::to_io)?; drop(tree_update); // Verify all updates via iterator @@ -4704,7 +4704,7 @@ mod tests { .map(|(k, v)| (k, v)) .collect(); - tree_update.update_batch(&update_refs).map_err(|e| e.to_io())?; + tree_update.update_batch(&update_refs).map_err(BPlusTreeError::to_io)?; let size_before_compact = std::fs::metadata(&filepath)?.len(); @@ -4756,9 +4756,9 @@ mod tests { // Verify all data is present in the NEW file let mut tree_check = BPlusTreeQuery::::try_new(&filepath)?; - assert!(tree_check.query(&1).map_err(|e| e.to_io())?.is_some(), "Should have key 1"); - assert!(tree_check.query(&2).map_err(|e| e.to_io())?.is_some(), "Should have key 2"); - assert!(tree_check.query(&3).map_err(|e| e.to_io())?.is_some(), "Should have key 3 - if missing, file handle wasn't updated"); + assert!(tree_check.query(&1).map_err(BPlusTreeError::to_io)?.is_some(), "Should have key 1"); + assert!(tree_check.query(&2).map_err(BPlusTreeError::to_io)?.is_some(), "Should have key 2"); + assert!(tree_check.query(&3).map_err(BPlusTreeError::to_io)?.is_some(), "Should have key 3 - if missing, file handle wasn't updated"); Ok(()) } @@ -4935,10 +4935,11 @@ mod tests { // Expected size without packing: // 1000 items * 4096 bytes/block = 4,096,000 bytes (~4MB) // Plus internal nodes - let unpacked_size_estimate = count as u64 * super::PAGE_SIZE_USIZE as u64; + let unpacked_size_estimate = + u64::from(count) * u64::try_from(super::PAGE_SIZE_USIZE).unwrap(); - println!("File size with packing: {} bytes", file_size); - println!("Estimated unpacked size: {} bytes", unpacked_size_estimate); + println!("File size with packing: {file_size} bytes"); + println!("Estimated unpacked size: {unpacked_size_estimate} bytes"); // We expect significant savings. // 1000 items * ~60 bytes / 4096 bytes/block ~= 15 blocks @@ -5008,7 +5009,7 @@ mod tests { let val1 = "A".repeat(10000); let val2 = "B".repeat(10000); - let updates = vec![ + let updates = [ (1, val1.clone()), (2, val2.clone()), ]; @@ -5072,7 +5073,7 @@ mod tests { let mut tree_update = BPlusTreeUpdate::::try_new(&filepath)?; // Batch contains same key multiple times - let updates = vec![ + let updates = [ (1, "First".to_string()), (1, "Second".to_string()), (2, "Two".to_string()), @@ -5117,7 +5118,7 @@ mod tests { let size_before = std::fs::metadata(&filepath)?.len(); // Each individual update writes a full path, increasing file size significantly. - assert!(size_before > count as u64 * 4000); + assert!(size_before > u64::from(count) * 4000); // Now Compact tree_update.compact(&filepath)?; @@ -5127,7 +5128,7 @@ mod tests { // 200 items * 100 bytes = 20KB payload. // Should pack into ~5-6 blocks (4KB each). - println!("Size before: {}, Size after: {}", size_before, size_after); + println!("Size before: {size_before}, Size after: {size_after}"); assert!(size_after < size_before / 10, "Compaction should pack values"); assert!(size_after < 100 * 1024, "File should be small"); // < 100KB @@ -5208,7 +5209,7 @@ mod tests { let keys: Vec = (0..count).collect(); let value_info: Vec = (0..count) .map(|i| ValueInfo { - mode: ValueStorageMode::Packed(i as u64 * 4096, (i % 16) as u16), + mode: ValueStorageMode::Packed(u64::from(i) * 4096, (i % 16) as u16), length: 100, cache: Mutex::new(None), }) @@ -5277,7 +5278,7 @@ mod tests { // File size should have grown slightly (promoted values written at EOF) // but not dramatically since most values are still packed - println!("Size initial: {}, Size after: {}", size_initial, size_after); + println!("Size initial: {size_initial}, Size after: {size_after}"); assert!(size_after >= size_initial, "File should not shrink"); // Verify all data is correct @@ -5303,7 +5304,7 @@ mod tests { let mut tree = BPlusTree::::new(); for i in 0..10 { - tree.insert(i, format!("value_{}", i)); + tree.insert(i, format!("value_{i}")); } tree.store(&filepath)?; @@ -5312,12 +5313,12 @@ mod tests { // Test None policy - should not error update.flush_policy = super::FlushPolicy::None; for i in 0..5 { - update.update(&i, format!("new_{}", i)).map_err(super::BPlusTreeError::to_io)?; + update.update(&i, format!("new_{i}")).map_err(super::BPlusTreeError::to_io)?; } // Verify values within same session for i in 0..5 { - assert_eq!(update.query(&i).map_err(super::BPlusTreeError::to_io)?.unwrap(), format!("new_{}", i)); + assert_eq!(update.query(&i).map_err(super::BPlusTreeError::to_io)?.unwrap(), format!("new_{i}")); } // Test Batch policy @@ -5424,8 +5425,8 @@ mod tests { let page = SlottedPage::new(&mut data, PageType::Leaf).expect("Init failed"); assert_eq!(page.header.page_type, PageType::Leaf); assert_eq!(page.header.cell_count, 0); - assert_eq!(page.header.free_start, PAGE_HEADER_SIZE as u16); - assert_eq!(page.header.free_end, PAGE_SIZE as u16); + assert_eq!(page.header.free_start, PAGE_HEADER_SIZE); + assert_eq!(page.header.free_end, PAGE_SIZE); assert_eq!(page.free_space(), PAGE_SIZE_USIZE - PAGE_HEADER_SIZE_USIZE); } @@ -5439,11 +5440,11 @@ mod tests { // Insert length-prefixed for test realism let mut cell1 = Vec::new(); - cell1.extend_from_slice(&(val1.len() as u32).to_le_bytes()); + cell1.extend_from_slice(&u32::try_from(val1.len()).unwrap().to_le_bytes()); cell1.extend_from_slice(val1); let mut cell2 = Vec::new(); - cell2.extend_from_slice(&(val2.len() as u32).to_le_bytes()); + cell2.extend_from_slice(&u32::try_from(val2.len()).unwrap().to_le_bytes()); cell2.extend_from_slice(val2); page.insert_at_index(0, &cell1).unwrap(); @@ -5465,7 +5466,7 @@ mod tests { let payload = vec![0xAAu8; 500]; let mut cell = Vec::new(); - cell.extend_from_slice(&(payload.len() as u32).to_le_bytes()); + cell.extend_from_slice(&u32::try_from(payload.len()).unwrap().to_le_bytes()); cell.extend_from_slice(&payload); for i in 0..6 { @@ -5496,7 +5497,7 @@ mod tests { // Case 1: Split single item page -> Should return None (no-op) let val = b"item"; let mut cell = Vec::new(); - cell.extend_from_slice(&(val.len() as u32).to_le_bytes()); + cell.extend_from_slice(&u32::try_from(val.len()).unwrap().to_le_bytes()); cell.extend_from_slice(val); page.insert_at_index(0, &cell).unwrap(); @@ -5506,7 +5507,7 @@ mod tests { assert_eq!(page.header.cell_count, 1); // Original page untouched } Ok(Some(_)) => panic!("Split of single item should result in None"), - Err(e) => panic!("Split of single item should result in no-op, not error: {:?}", e), + Err(e) => panic!("Split of single item should result in no-op, not error: {e:?}"), } } @@ -5535,4 +5536,3 @@ mod tests { Ok(()) } } - diff --git a/backend/src/repository/bplustree_stress.rs b/backend/src/repository/bplustree_stress.rs index 122a5d648..c62cc5b8c 100644 --- a/backend/src/repository/bplustree_stress.rs +++ b/backend/src/repository/bplustree_stress.rs @@ -1,6 +1,7 @@ use super::bplustree::{BPlusTree, BPlusTreeUpdate, BPlusTreeQuery}; use rand::prelude::*; use rand::distr::Alphanumeric; +use std::io::Write; use std::time::Instant; use tempfile::NamedTempFile; @@ -15,12 +16,17 @@ fn random_string(len: usize) -> String { } #[test] +#[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::too_many_lines +)] fn stress_test_bplustree() { let temp_file = NamedTempFile::new().unwrap(); let filepath = temp_file.path().to_path_buf(); let log_path = std::path::Path::new("/tmp/stress_results.txt"); let mut log_file = std::fs::File::create(log_path).unwrap(); - use std::io::Write; // Config let num_items = 500_000; @@ -29,7 +35,7 @@ fn stress_test_bplustree() { let large_val_len = 500; // Larger than packed limit (256) writeln!(log_file, "=== B+Tree Stress Test & Performance Analysis ===").unwrap(); - writeln!(log_file, "Dataset: {} items", num_items).unwrap(); + writeln!(log_file, "Dataset: {num_items} items").unwrap(); // ---------------------------------------------------------------- // Phase 1: Batch Insert (Sequential Keys) @@ -50,7 +56,7 @@ fn stress_test_bplustree() { tree.insert(k, v); } let insert_duration = start.elapsed(); - writeln!(log_file, "Insert Time: {:.2?}", insert_duration).unwrap(); + writeln!(log_file, "Insert Time: {insert_duration:.2?}").unwrap(); writeln!(log_file, "Throughput: {:.0} ops/sec", num_items as f64 / insert_duration.as_secs_f64()).unwrap(); // Prepare query keys @@ -61,13 +67,13 @@ fn stress_test_bplustree() { // ---------------------------------------------------------------- // Phase 1b: Memory-Only Random Query (Before storing) // ---------------------------------------------------------------- - writeln!(log_file, "\n[Phase 1b] Memory-Only Random Query ({} items)...", query_count).unwrap(); + writeln!(log_file, "\n[Phase 1b] Memory-Only Random Query ({query_count} items)...").unwrap(); let start = Instant::now(); for k in query_subset_mem { let _ = tree.query(k); } let duration = start.elapsed(); - writeln!(log_file, "Time: {:.2?}", duration).unwrap(); + writeln!(log_file, "Time: {duration:.2?}").unwrap(); writeln!(log_file, "Throughput: {:.0} ops/sec", query_count as f64 / duration.as_secs_f64()).unwrap(); // ---------------------------------------------------------------- @@ -78,21 +84,21 @@ fn stress_test_bplustree() { tree.store(&filepath).unwrap(); drop(tree); let duration = start.elapsed(); - writeln!(log_file, "Write Time: {:.2?}", duration).unwrap(); + writeln!(log_file, "Write Time: {duration:.2?}").unwrap(); let size_phase1 = std::fs::metadata(&filepath).unwrap().len(); writeln!(log_file, "File Size: {:.2} MB", size_phase1 as f64 / 1024.0 / 1024.0).unwrap(); // ---------------------------------------------------------------- // Phase 2: Random Query (Disk-based) // ---------------------------------------------------------------- - writeln!(log_file, "\n[Phase 2] Random Query Disk-based ({} items)...", query_count).unwrap(); + writeln!(log_file, "\n[Phase 2] Random Query Disk-based ({query_count} items)...").unwrap(); let mut query = BPlusTreeQuery::::try_new(&filepath).unwrap(); let start = Instant::now(); for k in query_subset_mem { let _ = query.query_zero_copy(k).unwrap(); } let duration = start.elapsed(); - writeln!(log_file, "Time: {:.2?}", duration).unwrap(); + writeln!(log_file, "Time: {duration:.2?}").unwrap(); writeln!(log_file, "Throughput: {:.0} ops/sec", query_count as f64 / duration.as_secs_f64()).unwrap(); // ---------------------------------------------------------------- @@ -105,11 +111,11 @@ fn stress_test_bplustree() { .map(|&k| (k, random_string(small_val_len))) .collect(); let update_refs: Vec<(&u32, &String)> = updates.iter().map(|(k,v)| (k,v)).collect(); - let mut updater = BPlusTreeUpdate::::try_new(&filepath).unwrap(); + let mut tree_updater = BPlusTreeUpdate::::try_new(&filepath).unwrap(); let start = Instant::now(); - updater.update_batch(&update_refs).unwrap(); + tree_updater.update_batch(&update_refs).unwrap(); let duration = start.elapsed(); - writeln!(log_file, "Time: {:.2?}", duration).unwrap(); + writeln!(log_file, "Time: {duration:.2?}").unwrap(); writeln!(log_file, "Throughput: {:.0} ops/sec", update_count as f64 / duration.as_secs_f64()).unwrap(); let size_phase3 = std::fs::metadata(&filepath).unwrap().len(); writeln!(log_file, "File Size: {:.2} MB", size_phase3 as f64 / 1024.0 / 1024.0).unwrap(); @@ -123,26 +129,32 @@ fn stress_test_bplustree() { .collect(); let update_refs_prom: Vec<(&u32, &String)> = updates_prom.iter().map(|(k,v)| (k,v)).collect(); let start = Instant::now(); - updater.update_batch(&update_refs_prom).unwrap(); + tree_updater.update_batch(&update_refs_prom).unwrap(); let duration = start.elapsed(); - writeln!(log_file, "Time: {:.2?}", duration).unwrap(); + writeln!(log_file, "Time: {duration:.2?}").unwrap(); writeln!(log_file, "Throughput: {:.0} ops/sec", update_count as f64 / duration.as_secs_f64()).unwrap(); let size_phase4 = std::fs::metadata(&filepath).unwrap().len(); writeln!(log_file, "File Size: {:.2} MB", size_phase4 as f64 / 1024.0 / 1024.0).unwrap(); - drop(updater); + drop(tree_updater); // ---------------------------------------------------------------- // Phase 5: Compaction // ---------------------------------------------------------------- writeln!(log_file, "\n[Phase 5] Compaction...").unwrap(); - let mut updater = BPlusTreeUpdate::::try_new(&filepath).unwrap(); + let mut tree_updater = BPlusTreeUpdate::::try_new(&filepath).unwrap(); let start = Instant::now(); - updater.compact(&filepath).unwrap(); + tree_updater.compact(&filepath).unwrap(); let duration = start.elapsed(); - writeln!(log_file, "Time: {:.2?}", duration).unwrap(); + writeln!(log_file, "Time: {duration:.2?}").unwrap(); let size_phase5 = std::fs::metadata(&filepath).unwrap().len(); - writeln!(log_file, "File Size: {:.2} MB (Reduction: {:.2} MB)", size_phase5 as f64 / 1024.0 / 1024.0, (size_phase4 as i64 - size_phase5 as i64) as f64 / 1024.0 / 1024.0).unwrap(); - drop(updater); + writeln!( + log_file, + "File Size: {:.2} MB (Reduction: {:.2} MB)", + size_phase5 as f64 / 1024.0 / 1024.0, + (size_phase4 as i64 - size_phase5 as i64) as f64 / 1024.0 / 1024.0 + ) + .unwrap(); + drop(tree_updater); // ---------------------------------------------------------------- // Phase 6: Full Tree Load and In-Memory Query @@ -151,13 +163,13 @@ fn stress_test_bplustree() { let start = Instant::now(); let tree_mem = BPlusTree::::load(&filepath).unwrap(); let load_duration = start.elapsed(); - writeln!(log_file, "Load Time: {:.2?}", load_duration).unwrap(); + writeln!(log_file, "Load Time: {load_duration:.2?}").unwrap(); let start = Instant::now(); for k in query_subset_mem { let _ = tree_mem.query(k); } let query_duration = start.elapsed(); - writeln!(log_file, "In-Memory Query Time: {:.2?}", query_duration).unwrap(); + writeln!(log_file, "In-Memory Query Time: {query_duration:.2?}").unwrap(); writeln!(log_file, "Throughput: {:.0} ops/sec", query_count as f64 / query_duration.as_secs_f64()).unwrap(); } diff --git a/backend/src/repository/sorted_index.rs b/backend/src/repository/sorted_index.rs index fabbeb3bb..1cb397ad3 100644 --- a/backend/src/repository/sorted_index.rs +++ b/backend/src/repository/sorted_index.rs @@ -664,7 +664,7 @@ mod tests { assert_eq!(offset, 100); assert_eq!(length, 50); } - _ => panic!("Expected Single location"), + ValueLocation::Packed { .. } => panic!("Expected Single location"), } assert_eq!(entries[1].sort_key, "banana".to_string()); @@ -675,7 +675,7 @@ mod tests { assert_eq!(index, 3); assert_eq!(length, 75); } - _ => panic!("Expected Packed location"), + ValueLocation::Single { .. } => panic!("Expected Packed location"), } assert_eq!(entries[2].sort_key, "cherry".to_string()); @@ -685,7 +685,7 @@ mod tests { assert_eq!(offset, 300); assert_eq!(length, 100); } - _ => panic!("Expected Single location"), + ValueLocation::Packed { .. } => panic!("Expected Single location"), } } diff --git a/backend/src/utils/epg_parser.rs b/backend/src/utils/epg_parser.rs index 2938954fe..ab1e20b65 100644 --- a/backend/src/utils/epg_parser.rs +++ b/backend/src/utils/epg_parser.rs @@ -117,47 +117,47 @@ mod tests { #[test] fn test_parse_timeshift() { assert!(matches!(parse_timeshift(Some(&String::from("2"))), EpgTimeShift::Fixed(120))); - assert!(matches!(parse_timeshift(Some(&String::from("-1:30"))), EpgTimeShift::Fixed(-90))); - assert!(matches!(parse_timeshift(Some(&String::from("+0:15"))), EpgTimeShift::Fixed(15))); - assert!(matches!(parse_timeshift(Some(&String::from("1:45"))), EpgTimeShift::Fixed(105))); - assert!(matches!(parse_timeshift(Some(&String::from(":45"))), EpgTimeShift::Fixed(45))); - assert!(matches!(parse_timeshift(Some(&String::from("-:45"))), EpgTimeShift::Fixed(-45))); - assert!(matches!(parse_timeshift(Some(&String::from("0:30"))), EpgTimeShift::Fixed(30))); - assert!(matches!(parse_timeshift(Some(&String::from(":3"))), EpgTimeShift::Fixed(3))); - assert!(matches!(parse_timeshift(Some(&String::from("2:"))), EpgTimeShift::Fixed(120))); - assert!(matches!(parse_timeshift(Some(&String::from("+2:00"))), EpgTimeShift::Fixed(120))); - assert!(matches!(parse_timeshift(Some(&String::from("-0:10"))), EpgTimeShift::Fixed(-10))); - assert!(matches!(parse_timeshift(Some(&String::from("invalid"))), EpgTimeShift::None)); - assert!(matches!(parse_timeshift(Some(&String::from("+abc"))), EpgTimeShift::None)); - assert!(matches!(parse_timeshift(Some(&String::new())), EpgTimeShift::None)); + assert!(matches!(parse_timeshift(Some("-1:30")), EpgTimeShift::Fixed(-90))); + assert!(matches!(parse_timeshift(Some("+0:15")), EpgTimeShift::Fixed(15))); + assert!(matches!(parse_timeshift(Some("1:45")), EpgTimeShift::Fixed(105))); + assert!(matches!(parse_timeshift(Some(":45")), EpgTimeShift::Fixed(45))); + assert!(matches!(parse_timeshift(Some("-:45")), EpgTimeShift::Fixed(-45))); + assert!(matches!(parse_timeshift(Some("0:30")), EpgTimeShift::Fixed(30))); + assert!(matches!(parse_timeshift(Some(":3")), EpgTimeShift::Fixed(3))); + assert!(matches!(parse_timeshift(Some("2:")), EpgTimeShift::Fixed(120))); + assert!(matches!(parse_timeshift(Some("+2:00")), EpgTimeShift::Fixed(120))); + assert!(matches!(parse_timeshift(Some("-0:10")), EpgTimeShift::Fixed(-10))); + assert!(matches!(parse_timeshift(Some("invalid")), EpgTimeShift::None)); + assert!(matches!(parse_timeshift(Some("+abc")), EpgTimeShift::None)); + assert!(matches!(parse_timeshift(Some("")), EpgTimeShift::None)); assert!(matches!(parse_timeshift(None), EpgTimeShift::None)); } #[test] fn test_parse_timezone() { // Check timezone parsing creates the correct variant - let amterdam = parse_timeshift(Some(&"Europe/Amsterdam".to_string())); + let amterdam = parse_timeshift(Some("Europe/Amsterdam")); if let EpgTimeShift::TimeZone(tz) = amterdam { assert_eq!(tz.name(), "Europe/Amsterdam"); } else { panic!("Expected TimeZone for Europe/Amsterdam"); } - let new_york = parse_timeshift(Some(&"America/New_York".to_string())); + let new_york = parse_timeshift(Some("America/New_York")); if let EpgTimeShift::TimeZone(tz) = new_york { assert_eq!(tz.name(), "America/New_York"); } else { panic!("Expected TimeZone for America/New_York"); } - let tokyo = parse_timeshift(Some(&"Asia/Tokyo".to_string())); + let tokyo = parse_timeshift(Some("Asia/Tokyo")); if let EpgTimeShift::TimeZone(tz) = tokyo { assert_eq!(tz.name(), "Asia/Tokyo"); } else { panic!("Expected TimeZone for Asia/Tokyo"); } - let utc = parse_timeshift(Some(&"UTC".to_string())); + let utc = parse_timeshift(Some("UTC")); if let EpgTimeShift::TimeZone(tz) = utc { assert_eq!(tz.name(), "UTC"); } else { diff --git a/frontend/src/app/components/playlist/assistant/playlist.rs b/frontend/src/app/components/playlist/assistant/playlist.rs index b28f82cc8..c5850e782 100644 --- a/frontend/src/app/components/playlist/assistant/playlist.rs +++ b/frontend/src/app/components/playlist/assistant/playlist.rs @@ -3,6 +3,7 @@ use std::str::FromStr; use yew::prelude::*; use crate::app::components::{NameStep, Panel, PlaylistAssistantContext, TypeStep}; +#[allow(dead_code)] enum PlaylistAssistantStep { Name, Type, @@ -58,4 +59,4 @@ pub fn PlaylistAssistant() -> Html { > } -} \ No newline at end of file +} diff --git a/frontend/src/app/components/playlist/assistant/playlist_assistant_context.rs b/frontend/src/app/components/playlist/assistant/playlist_assistant_context.rs index 7d8337579..8c409c803 100644 --- a/frontend/src/app/components/playlist/assistant/playlist_assistant_context.rs +++ b/frontend/src/app/components/playlist/assistant/playlist_assistant_context.rs @@ -1,6 +1,7 @@ use yew::UseStateHandle; #[derive(Clone, PartialEq)] +#[allow(dead_code)] pub struct PlaylistAssistantContext { pub custom_class: UseStateHandle, -} \ No newline at end of file +} diff --git a/shared/src/foundation/filter.rs b/shared/src/foundation/filter.rs index 7cb9ad7b1..b05957a58 100644 --- a/shared/src/foundation/filter.rs +++ b/shared/src/foundation/filter.rs @@ -718,7 +718,7 @@ mod tests { match get_filter(flt, None) { Ok(filter) => { assert_eq!(format!("{filter}"), flt); - let channels = vec![ + let channels = [ create_mock_pli("24/7: Cars", "FR Channels"), create_mock_pli("24/7: Cars", "US Channels"), create_mock_pli("Entertainment", "US Channels"), @@ -768,7 +768,7 @@ mod tests { match get_filter(flt, None) { Ok(filter) => { assert_eq!(format!("{filter}"), flt); - let channels = vec![ + let channels = [ create_mock_pli("NA", "GA"), create_mock_pli("NB", "GB"), create_mock_pli("NA", "GB"), @@ -833,7 +833,7 @@ mod tests { match get_filter(flt, None) { Ok(filter) => { assert_eq!(format!("{filter}"), flt); - let channels = vec![ + let channels = [ create_mock_pli("24/7: Cars", "FR Channels"), create_mock_pli("24/7: Cars", "US Channels"), create_mock_pli("Entertainment", "US Channels"),