// API測試 - 使用整合測試方式 // 因handler函數未公開,使用FileTree直接測試API邏輯 use markbase::filetree::node::NodeType; use markbase::filetree::{mode, FileTree}; use rusqlite::Connection; use uuid::Uuid; fn temp_db() -> (Connection, String) { let user_id = format!("test_api_{}", Uuid::new_v4()); let conn = FileTree::init_user_db(&user_id).unwrap(); (conn, user_id) } #[test] fn test_api_logic_create_folder() { let (conn, user_id) = temp_db(); let mut tree = FileTree::load(&conn, &user_id).unwrap(); let folder = FileTree::new_folder("API_Test_Folder", None); tree.insert_node(&conn, &folder).unwrap(); let loaded = FileTree::load(&conn, &user_id).unwrap(); assert_eq!(loaded.nodes.len(), 1); } #[test] fn test_api_logic_create_file() { let (conn, user_id) = temp_db(); let mut tree = FileTree::load(&conn, &user_id).unwrap(); let (file_node, register_sql) = FileTree::new_file_node( "test_api.mp4", "api_test_uuid", None, "test_api.mp4", Some(1024), Some("video/mp4"), None, None, ); if let Some(sql) = register_sql { conn.execute_batch(&sql).unwrap(); } tree.insert_node(&conn, &file_node).unwrap(); let loaded = FileTree::load(&conn, &user_id).unwrap(); assert_eq!(loaded.nodes.len(), 1); assert_eq!(loaded.nodes[0].node_type, NodeType::File); } #[test] fn test_api_logic_get_tree_with_mode() { let (conn, user_id) = temp_db(); let mut tree = FileTree::load(&conn, &user_id).unwrap(); let folder = FileTree::new_folder("Root", None); tree.insert_node(&conn, &folder).unwrap(); //測試不同顯示模式 let tree_mode = mode::get_mode("tree").unwrap(); let tree_rendered = tree_mode.render(&tree); assert!(tree_rendered["nodes"].is_array()); let list_mode = mode::get_mode("list").unwrap(); let list_rendered = list_mode.render(&tree); assert!(list_rendered["nodes"].is_array()); let grid_sm_mode = mode::get_mode("grid_sm").unwrap(); let grid_sm_rendered = grid_sm_mode.render(&tree); assert!(grid_sm_rendered["nodes"].is_array()); } #[test] fn test_api_logic_update_node() { let (conn, user_id) = temp_db(); let mut tree = FileTree::load(&conn, &user_id).unwrap(); let mut folder = FileTree::new_folder("Original", None); tree.insert_node(&conn, &folder).unwrap(); folder.label = "Updated_via_API".to_string(); folder.icon = Some("🎬".to_string()); tree.update_node(&conn, &folder.node_id, &folder).unwrap(); let loaded = FileTree::load(&conn, &user_id).unwrap(); assert_eq!(loaded.nodes[0].label, "Updated_via_API"); assert_eq!(loaded.nodes[0].icon, Some("🎬".to_string())); } #[test] fn test_api_logic_delete_node() { let (conn, user_id) = temp_db(); let mut tree = FileTree::load(&conn, &user_id).unwrap(); let folder = FileTree::new_folder("ToDelete", None); let node_id = folder.node_id.clone(); tree.insert_node(&conn, &folder).unwrap(); assert_eq!(tree.nodes.len(), 1); tree.delete_node(&conn, &node_id).unwrap(); let loaded = FileTree::load(&conn, &user_id).unwrap(); assert_eq!(loaded.nodes.len(), 0); } #[test] fn test_api_logic_delete_all_nodes() { let (conn, user_id) = temp_db(); let mut tree = FileTree::load(&conn, &user_id).unwrap(); for i in 1..=5 { let folder = FileTree::new_folder(&format!("Folder{}", i), None); tree.insert_node(&conn, &folder).unwrap(); } let loaded = FileTree::load(&conn, &user_id).unwrap(); assert_eq!(loaded.nodes.len(), 5); //模擬delete_all_nodes API邏輯 for node in &loaded.nodes { conn.execute( "DELETE FROM file_nodes WHERE node_id = ?1", rusqlite::params![node.node_id], ) .unwrap(); } let after_delete = FileTree::load(&conn, &user_id).unwrap(); assert_eq!(after_delete.nodes.len(), 0); } #[test] fn test_api_logic_move_node() { let (conn, user_id) = temp_db(); let mut tree = FileTree::load(&conn, &user_id).unwrap(); let parent = FileTree::new_folder("Parent", None); let child = FileTree::new_folder("Child", Some(parent.node_id.clone())); tree.insert_node(&conn, &parent).unwrap(); tree.insert_node(&conn, &child).unwrap(); //移動到根目錄 tree.move_node(&conn, &child.node_id, None).unwrap(); let loaded = FileTree::load(&conn, &user_id).unwrap(); let moved_node = loaded .nodes .iter() .find(|n| n.node_id == child.node_id) .unwrap(); assert!(moved_node.parent_id.is_none()); } #[test] fn test_api_logic_update_alias() { let (conn, user_id) = temp_db(); let mut tree = FileTree::load(&conn, &user_id).unwrap(); let folder = FileTree::new_folder("Videos", None); tree.insert_node(&conn, &folder).unwrap(); tree.update_node_alias(&conn, &folder.node_id, "zh_tw", "影片") .unwrap(); tree.update_node_alias(&conn, &folder.node_id, "en_us", "Videos") .unwrap(); let loaded = FileTree::load(&conn, &user_id).unwrap(); assert_eq!( loaded.nodes[0].aliases.get("zh_tw").map(|s| s.as_str()), Some("影片") ); assert_eq!( loaded.nodes[0].aliases.get("en_us").map(|s| s.as_str()), Some("Videos") ); } #[test] fn test_api_logic_nested_structure() { let (conn, user_id) = temp_db(); let mut tree = FileTree::load(&conn, &user_id).unwrap(); let root = FileTree::new_folder("Root", None); let level1 = FileTree::new_folder("Level1", Some(root.node_id.clone())); let level2 = FileTree::new_folder("Level2", Some(level1.node_id.clone())); tree.insert_node(&conn, &root).unwrap(); tree.insert_node(&conn, &level1).unwrap(); tree.insert_node(&conn, &level2).unwrap(); let loaded = FileTree::load(&conn, &user_id).unwrap(); assert_eq!(loaded.nodes.len(), 3); } #[test] fn test_api_logic_get_modes() { let modes = mode::list_modes(); assert_eq!(modes.len(), 4); let names: Vec<&str> = modes.iter().map(|m| m.name()).collect(); assert!(names.contains(&"tree")); assert!(names.contains(&"list")); assert!(names.contains(&"grid_sm")); assert!(names.contains(&"grid_lg")); } #[test] fn test_api_logic_file_info() { let (conn, _user_id) = temp_db(); let file_uuid = "test_file_uuid_123"; FileTree::add_location(&conn, file_uuid, "/path/to/file.mp4", Some("origin")).unwrap(); let location: String = conn .query_row( "SELECT location FROM file_locations WHERE file_uuid = ?1", [file_uuid], |row| row.get(0), ) .unwrap(); assert_eq!(location, "/path/to/file.mp4"); } #[test] fn test_api_logic_restore_scenario() { //模擬restore_tree API邏輯 let (conn, user_id) = temp_db(); let mut tree = FileTree::load(&conn, &user_id).unwrap(); //建立基本結構 let home = FileTree::new_folder("Home", None); let movies = FileTree::new_folder("Movies", Some(home.node_id.clone())); tree.insert_node(&conn, &home).unwrap(); tree.insert_node(&conn, &movies).unwrap(); let loaded = FileTree::load(&conn, &user_id).unwrap(); assert!(loaded.nodes.iter().any(|n| n.label == "Home")); assert!(loaded.nodes.iter().any(|n| n.label == "Movies")); }