1use crate::ref_format::{self, RefFormatError};
4
5crate::cow_str_newtype! {
6 pub struct Branch, BranchError(RefFormatError), "invalid branch name"
11}
12
13impl Branch {
14 #[must_use]
16 pub fn has_parents(&self) -> bool {
17 self.0.contains('/')
18 }
19
20 const fn validate(input: &str) -> Result<(), BranchError> {
21 match ref_format::validate(input) {
22 Ok(()) => Ok(()),
23 Err(error) => Err(BranchError(error)),
24 }
25 }
26}
27
28#[cfg(test)]
29mod tests {
30 use super::*;
31
32 #[test]
33 fn test_valid_branch() {
34 assert!("main".parse::<Branch>().is_ok());
35 assert!("feature/login".parse::<Branch>().is_ok());
36 assert!("feature/deeply/nested/branch".parse::<Branch>().is_ok());
37 assert!("fix-123".parse::<Branch>().is_ok());
38 }
39
40 #[test]
41 fn test_has_parents() {
42 assert!(!Branch::from_static_or_panic("main").has_parents());
43 assert!(Branch::from_static_or_panic("feature/login").has_parents());
44 }
45
46 #[test]
47 fn test_invalid_passes_through() {
48 assert!(matches!(
50 "".parse::<Branch>(),
51 Err(BranchError(RefFormatError::Empty))
52 ));
53 assert!(matches!(
54 "-branch".parse::<Branch>(),
55 Err(BranchError(RefFormatError::StartsWithDash))
56 ));
57 assert!(matches!(
58 "feature/.hidden".parse::<Branch>(),
59 Err(BranchError(RefFormatError::ComponentStartsWithDot))
60 ));
61 }
62
63 #[test]
64 fn test_from_static_or_panic() {
65 let branch = Branch::from_static_or_panic("main");
66 assert_eq!(branch.as_str(), "main");
67 }
68
69 #[test]
70 fn test_display() {
71 let branch: Branch = "feature/test".parse().unwrap();
72 assert_eq!(format!("{branch}"), "feature/test");
73 }
74
75 #[test]
76 fn test_as_ref_os_str() {
77 use std::ffi::OsStr;
78 let branch: Branch = "main".parse().unwrap();
79 let os_str: &OsStr = branch.as_ref();
80 assert_eq!(os_str, "main");
81 }
82
83 #[test]
84 fn test_serialize() {
85 let branch: Branch = "feature/login".parse().unwrap();
86 assert_eq!(serde_json::to_string(&branch).unwrap(), "\"feature/login\"");
87 }
88
89 #[test]
90 fn test_deserialize() {
91 let branch: Branch = serde_json::from_str("\"feature/login\"").unwrap();
92 assert_eq!(branch.as_str(), "feature/login");
93 }
94
95 #[test]
96 fn test_deserialize_invalid() {
97 assert!(serde_json::from_str::<Branch>("\"-bad\"").is_err());
98 }
99}