//! Copyright (c) 2022-2026 GitDataAi All rights reserved. use gitks::error::GitResult; use gitks::pb::object_selector::Selector; use gitks::pb::{ObjectName, ObjectSelector}; fn test_macro(selector: Option) -> GitResult { let result = gitks::resolve_revision!(selector); Ok(result) } fn test_macro_with_default(selector: Option, default: &str) -> GitResult { let result = gitks::resolve_revision!(selector, default); Ok(result) } #[test] fn test_resolve_revision_with_oid() { let selector = Some(ObjectSelector { selector: Some(Selector::Oid(gitks::pb::Oid { hex: "abc1234567890123456789012345678901234567".to_string(), value: vec![], format: gitks::pb::ObjectFormat::Sha1 as i32, })), }); let result = test_macro(selector).unwrap(); assert_eq!(result, "abc1234567890123456789012345678901234567"); } #[test] fn test_resolve_revision_with_valid_revision() { let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: "main".to_string(), })), }); let result = test_macro(selector).unwrap(); assert_eq!(result, "main"); } #[test] fn test_resolve_revision_with_valid_branch() { let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: "feature/new-api".to_string(), })), }); let result = test_macro(selector).unwrap(); assert_eq!(result, "feature/new-api"); } #[test] fn test_resolve_revision_with_head() { let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: "HEAD".to_string(), })), }); let result = test_macro(selector).unwrap(); assert_eq!(result, "HEAD"); } #[test] fn test_resolve_revision_with_ancestry() { let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: "main~3".to_string(), })), }); let result = test_macro(selector).unwrap(); assert_eq!(result, "main~3"); } #[test] fn test_resolve_revision_none_defaults_to_head() { let result = test_macro(None).unwrap(); assert_eq!(result, "HEAD"); } #[test] fn test_resolve_revision_with_custom_default() { let result = test_macro_with_default(None, "develop").unwrap(); assert_eq!(result, "develop"); } #[test] fn test_resolve_revision_empty_selector() { let selector = Some(ObjectSelector { selector: None }); let result = test_macro(selector).unwrap(); assert_eq!(result, "HEAD"); } #[test] fn test_resolve_revision_empty_with_custom_default() { let selector = Some(ObjectSelector { selector: None }); let result = test_macro_with_default(selector, "custom-branch").unwrap(); assert_eq!(result, "custom-branch"); } #[test] fn test_resolve_revision_rejects_dangerous() { let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: "branch;rm -rf /".to_string(), })), }); let result = test_macro(selector); assert!(result.is_err()); } #[test] fn test_resolve_revision_rejects_traversal() { let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: "../etc/passwd".to_string(), })), }); let result = test_macro(selector); assert!(result.is_err()); } #[test] fn test_resolve_revision_rejects_excessive_depth() { let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: "main~99999".to_string(), })), }); let result = test_macro(selector); assert!(result.is_err()); } #[test] fn test_resolve_revision_rejects_too_long() { let long_rev = "a".repeat(300); let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: long_rev })), }); let result = test_macro(selector); assert!(result.is_err()); } #[test] fn test_resolve_revision_accepts_valid_hex() { let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: "deadbeef1234567890abcdef".to_string(), })), }); let result = test_macro(selector).unwrap(); assert_eq!(result, "deadbeef1234567890abcdef"); } #[test] fn test_resolve_revision_accepts_ref_prefix() { let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: "ref:refs/heads/main".to_string(), })), }); let result = test_macro(selector).unwrap(); assert_eq!(result, "ref:refs/heads/main"); } #[test] fn test_resolve_revision_accepts_tree_suffix() { let selector = Some(ObjectSelector { selector: Some(Selector::Revision(ObjectName { revision: "main^{tree}".to_string(), })), }); let result = test_macro(selector).unwrap(); assert_eq!(result, "main^{tree}"); }