Files
markbase/tests/api_logic_test.rs
Warren e3d6b60825 feat: MarkBase initial version
Phase 1 (Infrastructure):
- Docs: README.md, AGENTS.md, CHANGELOG.md
- Tests: 26 tests (modes_test, filetree_api_test)
- Examples: examples/sample.md, sample.json
- CI/CD: .gitea/workflows/test.yml, release.yml
- Runner: configuration scripts and guides

Phase 2 (Quality):
- Code quality: rustfmt/clippy config
- Security: environment variables
- Test coverage: 62 tests (+36)
- Documentation: CONTRIBUTING.md, docs/api.yaml
- Showcase: demo_features.md, developer_quickstart.md

Test coverage: 75%
Test pass rate: 100%
2026-05-16 15:37:37 +08:00

249 lines
7.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// API測試 - 使用整合測試方式
// 因handler函數未公開使用FileTree直接測試API邏輯
use markbase::filetree::node::NodeType;
use markbase::filetree::{mode, FileTree};
use rusqlite::Connection;
use serde_json::json;
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"));
}