|
2 | 2 | // |
3 | 3 | // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 |
4 | 4 |
|
| 5 | +use std::path::PathBuf; |
| 6 | + |
| 7 | +use clap::Parser; |
| 8 | +use commitbee::cli::Cli; |
5 | 9 | use commitbee::config::{Config, Provider}; |
6 | 10 |
|
7 | 11 | // ─── Default values ────────────────────────────────────────────────────────── |
@@ -107,6 +111,141 @@ fn format_section_defaults() { |
107 | 111 | assert!(config.format.lowercase_subject); |
108 | 112 | } |
109 | 113 |
|
| 114 | +// ─── Exclude patterns ───────────────────────────────────────────────────────── |
| 115 | + |
| 116 | +#[test] |
| 117 | +fn exclude_patterns_default_empty() { |
| 118 | + let config = Config::default(); |
| 119 | + assert!(config.exclude_patterns.is_empty()); |
| 120 | +} |
| 121 | + |
| 122 | +#[test] |
| 123 | +fn exclude_patterns_from_toml() { |
| 124 | + let toml_str = r#" |
| 125 | +exclude_patterns = ["*.lock", "**/*.generated.*"] |
| 126 | +"#; |
| 127 | + let config: Config = toml::from_str(toml_str).unwrap(); |
| 128 | + assert_eq!(config.exclude_patterns.len(), 2); |
| 129 | + assert_eq!(config.exclude_patterns[0], "*.lock"); |
| 130 | + assert_eq!(config.exclude_patterns[1], "**/*.generated.*"); |
| 131 | +} |
| 132 | + |
| 133 | +#[test] |
| 134 | +fn exclude_patterns_empty_list_from_toml() { |
| 135 | + let toml_str = r#" |
| 136 | +exclude_patterns = [] |
| 137 | +"#; |
| 138 | + let config: Config = toml::from_str(toml_str).unwrap(); |
| 139 | + assert!(config.exclude_patterns.is_empty()); |
| 140 | +} |
| 141 | + |
| 142 | +// ─── Exclude pattern glob matching ──────────────────────────────────────────── |
| 143 | + |
| 144 | +#[test] |
| 145 | +fn exclude_glob_matches_lock_files() { |
| 146 | + use globset::{Glob, GlobSetBuilder}; |
| 147 | + |
| 148 | + let patterns = vec!["*.lock".to_string()]; |
| 149 | + let mut builder = GlobSetBuilder::new(); |
| 150 | + for p in &patterns { |
| 151 | + builder.add(Glob::new(p).unwrap()); |
| 152 | + } |
| 153 | + let set = builder.build().unwrap(); |
| 154 | + |
| 155 | + assert!(set.is_match(PathBuf::from("Cargo.lock"))); |
| 156 | + assert!(set.is_match(PathBuf::from("yarn.lock"))); |
| 157 | + assert!(!set.is_match(PathBuf::from("package-lock.json"))); |
| 158 | + assert!(!set.is_match(PathBuf::from("src/main.rs"))); |
| 159 | +} |
| 160 | + |
| 161 | +#[test] |
| 162 | +fn exclude_glob_matches_nested_generated() { |
| 163 | + use globset::{Glob, GlobSetBuilder}; |
| 164 | + |
| 165 | + let patterns = vec!["**/*.generated.*".to_string()]; |
| 166 | + let mut builder = GlobSetBuilder::new(); |
| 167 | + for p in &patterns { |
| 168 | + builder.add(Glob::new(p).unwrap()); |
| 169 | + } |
| 170 | + let set = builder.build().unwrap(); |
| 171 | + |
| 172 | + assert!(set.is_match(PathBuf::from("src/schema.generated.rs"))); |
| 173 | + assert!(set.is_match(PathBuf::from("deep/nested/file.generated.ts"))); |
| 174 | + assert!(!set.is_match(PathBuf::from("src/main.rs"))); |
| 175 | +} |
| 176 | + |
| 177 | +#[test] |
| 178 | +fn exclude_glob_multiple_patterns() { |
| 179 | + use globset::{Glob, GlobSetBuilder}; |
| 180 | + |
| 181 | + let patterns = vec!["*.lock".to_string(), "*.min.js".to_string()]; |
| 182 | + let mut builder = GlobSetBuilder::new(); |
| 183 | + for p in &patterns { |
| 184 | + builder.add(Glob::new(p).unwrap()); |
| 185 | + } |
| 186 | + let set = builder.build().unwrap(); |
| 187 | + |
| 188 | + assert!(set.is_match(PathBuf::from("Cargo.lock"))); |
| 189 | + assert!(set.is_match(PathBuf::from("bundle.min.js"))); |
| 190 | + assert!(!set.is_match(PathBuf::from("src/app.js"))); |
| 191 | +} |
| 192 | + |
| 193 | +#[test] |
| 194 | +fn exclude_glob_directory_pattern() { |
| 195 | + use globset::{Glob, GlobSetBuilder}; |
| 196 | + |
| 197 | + let patterns = vec!["vendor/**".to_string()]; |
| 198 | + let mut builder = GlobSetBuilder::new(); |
| 199 | + for p in &patterns { |
| 200 | + builder.add(Glob::new(p).unwrap()); |
| 201 | + } |
| 202 | + let set = builder.build().unwrap(); |
| 203 | + |
| 204 | + assert!(set.is_match(PathBuf::from("vendor/lib.rs"))); |
| 205 | + assert!(set.is_match(PathBuf::from("vendor/deep/nested.rs"))); |
| 206 | + assert!(!set.is_match(PathBuf::from("src/vendor.rs"))); |
| 207 | +} |
| 208 | + |
| 209 | +// ─── CLI flag parsing ───────────────────────────────────────────────────────── |
| 210 | + |
| 211 | +#[test] |
| 212 | +fn cli_exclude_single() { |
| 213 | + let cli = Cli::try_parse_from(["commitbee", "--exclude", "*.lock"]).unwrap(); |
| 214 | + assert_eq!(cli.exclude, vec!["*.lock"]); |
| 215 | +} |
| 216 | + |
| 217 | +#[test] |
| 218 | +fn cli_exclude_multiple() { |
| 219 | + let cli = |
| 220 | + Cli::try_parse_from(["commitbee", "--exclude", "*.lock", "--exclude", "*.min.js"]).unwrap(); |
| 221 | + assert_eq!(cli.exclude, vec!["*.lock", "*.min.js"]); |
| 222 | +} |
| 223 | + |
| 224 | +#[test] |
| 225 | +fn cli_exclude_empty_by_default() { |
| 226 | + let cli = Cli::try_parse_from(["commitbee"]).unwrap(); |
| 227 | + assert!(cli.exclude.is_empty()); |
| 228 | +} |
| 229 | + |
| 230 | +#[test] |
| 231 | +fn cli_clipboard_flag() { |
| 232 | + let cli = Cli::try_parse_from(["commitbee", "--clipboard"]).unwrap(); |
| 233 | + assert!(cli.clipboard); |
| 234 | +} |
| 235 | + |
| 236 | +#[test] |
| 237 | +fn cli_clipboard_default_false() { |
| 238 | + let cli = Cli::try_parse_from(["commitbee"]).unwrap(); |
| 239 | + assert!(!cli.clipboard); |
| 240 | +} |
| 241 | + |
| 242 | +#[test] |
| 243 | +fn cli_clipboard_with_dry_run() { |
| 244 | + let cli = Cli::try_parse_from(["commitbee", "--clipboard", "--dry-run"]).unwrap(); |
| 245 | + assert!(cli.clipboard); |
| 246 | + assert!(cli.dry_run); |
| 247 | +} |
| 248 | + |
110 | 249 | // ─── Error handling ────────────────────────────────────────────────────────── |
111 | 250 |
|
112 | 251 | #[test] |
|
0 commit comments