Skip to main content

git_spawn/parse/
notes.rs

1//! Parser for `git notes list`.
2//!
3//! `git notes list` emits one `<note-object-sha> <annotated-object-sha>` pair
4//! per line (e.g. `5b8d8870... 04190777...`). This parser turns that into
5//! `(note_sha, object_sha)` tuples. It is permissive: blank lines are skipped
6//! and lines without a second field are ignored rather than erroring.
7
8/// Parse the output of `git notes list`.
9///
10/// Returns one `(note_sha, object_sha)` tuple per well-formed line. Lines that
11/// do not contain two whitespace-separated fields are skipped.
12///
13/// # Example
14/// ```
15/// use git_spawn::parse::parse_notes_list;
16/// let input = "5b8d8870 04190777\nabc123 def456\n";
17/// let pairs = parse_notes_list(input);
18/// assert_eq!(pairs.len(), 2);
19/// assert_eq!(pairs[0], ("5b8d8870".to_string(), "04190777".to_string()));
20/// assert_eq!(pairs[1].1, "def456");
21/// ```
22#[must_use]
23pub fn parse_notes_list(input: &str) -> Vec<(String, String)> {
24    input
25        .lines()
26        .filter_map(|line| {
27            let mut parts = line.split_whitespace();
28            let note = parts.next()?;
29            let object = parts.next()?;
30            Some((note.to_string(), object.to_string()))
31        })
32        .collect()
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38
39    #[test]
40    fn parses_pairs() {
41        let input = "note1 obj1\nnote2 obj2\n";
42        let pairs = parse_notes_list(input);
43        assert_eq!(pairs.len(), 2);
44        assert_eq!(pairs[0], ("note1".to_string(), "obj1".to_string()));
45        assert_eq!(pairs[1], ("note2".to_string(), "obj2".to_string()));
46    }
47
48    #[test]
49    fn skips_blank_and_malformed_lines() {
50        let input = "\nnote1 obj1\nlonely\n";
51        let pairs = parse_notes_list(input);
52        assert_eq!(pairs.len(), 1);
53        assert_eq!(pairs[0].0, "note1");
54    }
55
56    #[test]
57    fn empty_input() {
58        assert!(parse_notes_list("").is_empty());
59    }
60}