Files
galaxy/crates/galaxy_util/src/worktree_names_tests.rs
T

169 lines
5.7 KiB
Rust

use std::collections::HashSet;
use rand::prelude::StdRng;
use rand::SeedableRng;
use super::{generate_unique_name, WORDS};
fn seeded_rng(seed: u64) -> StdRng {
StdRng::seed_from_u64(seed)
}
#[test]
fn deterministic_output_with_seeded_rng() {
let existing = HashSet::new();
let a = generate_unique_name(&existing, &mut seeded_rng(42));
let b = generate_unique_name(&existing, &mut seeded_rng(42));
assert_eq!(a, b, "same seed should produce the same name");
}
#[test]
fn format_is_two_hyphenated_words() {
let existing = HashSet::new();
let name = generate_unique_name(&existing, &mut seeded_rng(1));
let parts: Vec<&str> = WORDS
.iter()
.copied()
.filter(|w| name.starts_with(&format!("{w}-")) || name.ends_with(&format!("-{w}")))
.collect();
// Instead of splitting on `-` (which would break hyphenated words like
// `palo-verde`), verify that the name starts with one word, ends with
// another, and those two words are distinct.
let word_set: HashSet<&str> = WORDS.iter().copied().collect();
let found_prefix = word_set
.iter()
.find(|w| name.starts_with(*w) && name.len() > w.len() && name.as_bytes()[w.len()] == b'-');
let found_suffix = word_set.iter().find(|w| {
name.ends_with(*w)
&& name.len() > w.len()
&& name.as_bytes()[name.len() - w.len() - 1] == b'-'
});
assert!(
found_prefix.is_some(),
"name should start with a word from WORDS: {name}"
);
assert!(
found_suffix.is_some(),
"name should end with a word from WORDS: {name}"
);
assert_ne!(
found_prefix.unwrap(),
found_suffix.unwrap(),
"the two words should be distinct: {name}"
);
assert!(
!parts.is_empty(),
"name should contain words from WORDS: {name}"
);
}
#[test]
fn words_are_distinct() {
let existing = HashSet::new();
for seed in 0..100 {
let name = generate_unique_name(&existing, &mut seeded_rng(seed));
// For a 2-word name, `choose_multiple` guarantees distinct indices,
// so the two words will always be different. Verify by checking that
// the name is not a word repeated (e.g. "mesa-mesa").
let word_set: HashSet<&str> = WORDS.iter().copied().collect();
for word in &word_set {
let repeated = format!("{word}-{word}");
assert_ne!(name, repeated, "generated name should never repeat a word");
}
}
}
#[test]
fn avoids_existing_branches() {
let mut existing = HashSet::new();
let mut rng = seeded_rng(7);
// Generate a name, add it to existing, then generate again —
// the second name must differ.
let first = generate_unique_name(&existing, &mut rng);
existing.insert(first.as_str());
let mut rng2 = seeded_rng(7);
let second = generate_unique_name(&existing, &mut rng2);
assert_ne!(first, second, "second name should avoid the first");
assert!(
!existing.contains(second.as_str()),
"second name should not be in existing set"
);
}
#[test]
fn escalates_to_three_words_when_two_word_space_exhausted() {
// Fill existing with all possible 2-word combos (198 * 197 = 39006).
// This is a large set but the test verifies the escalation logic.
let word_set: Vec<&str> = WORDS.to_vec();
let mut existing = HashSet::new();
for (i, a) in word_set.iter().enumerate() {
for (j, b) in word_set.iter().enumerate() {
if i != j {
existing.insert(format!("{a}-{b}"));
}
}
}
let existing_refs: HashSet<&str> = existing.iter().map(|s| s.as_str()).collect();
let name = generate_unique_name(&existing_refs, &mut seeded_rng(99));
// The name should have 3 words (3+ hyphens when words themselves may
// contain hyphens, so count words by checking the word list).
let mut remaining = name.as_str();
let mut word_count = 0;
while !remaining.is_empty() {
// Find the longest matching word at the start of `remaining`.
let matched = word_set
.iter()
.filter(|w| remaining.starts_with(**w))
.max_by_key(|w| w.len());
match matched {
Some(w) => {
word_count += 1;
remaining = &remaining[w.len()..];
if remaining.starts_with('-') {
remaining = &remaining[1..];
}
}
None => {
panic!("name contains a segment not in WORDS: remaining={remaining}, full={name}")
}
}
}
assert!(
word_count >= 3,
"expected >=3 words when 2-word space is exhausted, got {word_count} in {name}"
);
}
#[test]
fn all_words_are_valid_git_branch_components() {
for word in WORDS {
assert!(!word.is_empty(), "word must not be empty");
assert!(
!word.starts_with('-'),
"word must not start with hyphen: {word}"
);
assert!(
!word.ends_with('-'),
"word must not end with hyphen: {word}"
);
assert!(!word.contains(".."), "word must not contain '..': {word}");
assert!(!word.contains(' '), "word must not contain spaces: {word}");
assert!(
!word.contains(|c: char| c.is_ascii_control()),
"word must not contain control chars: {word}"
);
assert!(
word.chars().all(|c| c.is_ascii_lowercase() || c == '-'),
"word must be lowercase ascii + hyphens: {word}"
);
}
}
#[test]
fn word_list_has_no_duplicates() {
let mut seen = HashSet::new();
for word in WORDS {
assert!(seen.insert(word), "duplicate word in WORDS: {word}");
}
}