test_integration.rs (11136B)
1 mod common; 2 3 use assert_cmd::Command; 4 use predicates::prelude::*; 5 use tempfile::TempDir; 6 7 fn xlcat() -> Command { 8 Command::cargo_bin("xlcat").unwrap() 9 } 10 11 #[test] 12 fn test_simple_file_default() { 13 let dir = TempDir::new().unwrap(); 14 let path = dir.path().join("simple.xlsx"); 15 common::create_simple(&path); 16 17 xlcat() 18 .arg(path.to_str().unwrap()) 19 .assert() 20 .success() 21 .stdout(predicate::str::contains("# File:")) 22 .stdout(predicate::str::contains("# Sheets: 1")) 23 .stdout(predicate::str::contains("## Sheet: Data")) 24 .stdout(predicate::str::contains("| name")) 25 .stdout(predicate::str::contains("| Alice")); 26 } 27 28 #[test] 29 fn test_schema_mode() { 30 let dir = TempDir::new().unwrap(); 31 let path = dir.path().join("simple.xlsx"); 32 common::create_simple(&path); 33 34 xlcat() 35 .arg("--schema") 36 .arg(path.to_str().unwrap()) 37 .assert() 38 .success() 39 .stdout(predicate::str::contains("| Column")) 40 .stdout(predicate::str::contains("| name")) 41 .stdout(predicate::str::contains("Alice").not()); 42 } 43 44 #[test] 45 fn test_multi_sheet_default_lists_schemas() { 46 let dir = TempDir::new().unwrap(); 47 let path = dir.path().join("multi.xlsx"); 48 common::create_multi_sheet(&path); 49 50 xlcat() 51 .arg(path.to_str().unwrap()) 52 .assert() 53 .success() 54 .stdout(predicate::str::contains("# Sheets: 3")) 55 .stdout(predicate::str::contains("## Sheet: Revenue")) 56 .stdout(predicate::str::contains("## Sheet: Expenses")) 57 .stdout(predicate::str::contains("## Sheet: Summary")) 58 .stdout(predicate::str::contains("Use --sheet")); 59 } 60 61 #[test] 62 fn test_multi_sheet_select_by_name() { 63 let dir = TempDir::new().unwrap(); 64 let path = dir.path().join("multi.xlsx"); 65 common::create_multi_sheet(&path); 66 67 xlcat() 68 .arg("--sheet") 69 .arg("Revenue") 70 .arg(path.to_str().unwrap()) 71 .assert() 72 .success() 73 .stdout(predicate::str::contains("| region |")) 74 .stdout(predicate::str::contains("| Region 1 |")); 75 } 76 77 #[test] 78 fn test_multi_sheet_select_by_index() { 79 let dir = TempDir::new().unwrap(); 80 let path = dir.path().join("multi.xlsx"); 81 common::create_multi_sheet(&path); 82 83 xlcat() 84 .arg("--sheet") 85 .arg("1") 86 .arg(path.to_str().unwrap()) 87 .assert() 88 .success() 89 .stdout(predicate::str::contains("## Sheet: Expenses")); 90 } 91 92 #[test] 93 fn test_head_tail_adaptive() { 94 let dir = TempDir::new().unwrap(); 95 let path = dir.path().join("many.xlsx"); 96 common::create_many_rows(&path); 97 98 xlcat() 99 .arg(path.to_str().unwrap()) 100 .assert() 101 .success() 102 .stdout(predicate::str::contains("rows omitted")); 103 } 104 105 #[test] 106 fn test_head_flag() { 107 let dir = TempDir::new().unwrap(); 108 let path = dir.path().join("many.xlsx"); 109 common::create_many_rows(&path); 110 111 xlcat() 112 .arg("--head") 113 .arg("3") 114 .arg(path.to_str().unwrap()) 115 .assert() 116 .success() 117 .stdout(predicate::str::contains("omitted").not()); 118 } 119 120 #[test] 121 fn test_csv_mode() { 122 let dir = TempDir::new().unwrap(); 123 let path = dir.path().join("simple.xlsx"); 124 common::create_simple(&path); 125 126 xlcat() 127 .arg("--csv") 128 .arg(path.to_str().unwrap()) 129 .assert() 130 .success() 131 .stdout(predicate::str::contains("# File:").not()) 132 .stdout(predicate::str::contains("name,")); 133 } 134 135 #[test] 136 fn test_invalid_flag_combo() { 137 let dir = TempDir::new().unwrap(); 138 let path = dir.path().join("simple.xlsx"); 139 common::create_simple(&path); 140 141 xlcat() 142 .arg("--schema") 143 .arg("--head") 144 .arg("10") 145 .arg(path.to_str().unwrap()) 146 .assert() 147 .code(2) 148 .stderr(predicate::str::contains("cannot be combined")); 149 } 150 151 #[test] 152 fn test_file_not_found() { 153 xlcat() 154 .arg("/nonexistent.xlsx") 155 .assert() 156 .failure() 157 .stderr(predicate::str::contains("Cannot")); 158 } 159 160 #[test] 161 fn test_empty_sheet() { 162 let dir = TempDir::new().unwrap(); 163 let path = dir.path().join("empty.xlsx"); 164 common::create_empty_sheet(&path); 165 166 xlcat() 167 .arg(path.to_str().unwrap()) 168 .assert() 169 .success() 170 .stdout(predicate::str::contains("empty")); 171 } 172 173 #[test] 174 fn test_describe_mode() { 175 let dir = TempDir::new().unwrap(); 176 let path = dir.path().join("simple.xlsx"); 177 common::create_simple(&path); 178 179 xlcat() 180 .arg(path.to_str().unwrap()) 181 .arg("--describe") 182 .assert() 183 .success() 184 .stdout(predicate::str::contains("count")) 185 .stdout(predicate::str::contains("mean")); 186 } 187 188 #[test] 189 fn test_all_without_sheet_on_multi() { 190 let dir = TempDir::new().unwrap(); 191 let path = dir.path().join("multi.xlsx"); 192 common::create_multi_sheet(&path); 193 194 xlcat() 195 .arg("--all") 196 .arg(path.to_str().unwrap()) 197 .assert() 198 .failure() 199 .stderr(predicate::str::contains("Multiple sheets")); 200 } 201 202 #[test] 203 fn test_large_file_gate_triggers() { 204 let dir = TempDir::new().unwrap(); 205 let path = dir.path().join("many.xlsx"); 206 common::create_many_rows(&path); 207 208 // Set max-size very low so gate triggers 209 xlcat() 210 .arg(path.to_str().unwrap()) 211 .arg("--max-size") 212 .arg("1K") 213 .assert() 214 .success() 215 .stdout(predicate::str::contains("Large file")); 216 } 217 218 #[test] 219 fn test_large_file_gate_overridden_by_head() { 220 let dir = TempDir::new().unwrap(); 221 let path = dir.path().join("many.xlsx"); 222 common::create_many_rows(&path); 223 224 let output = xlcat() 225 .arg(path.to_str().unwrap()) 226 .arg("--max-size") 227 .arg("1K") 228 .arg("--head") 229 .arg("5") 230 .assert() 231 .success(); 232 233 let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap(); 234 assert!(!stdout.contains("Large file")); 235 } 236 237 #[test] 238 fn test_large_file_gate_overridden_by_all() { 239 let dir = TempDir::new().unwrap(); 240 let path = dir.path().join("many.xlsx"); 241 common::create_many_rows(&path); 242 243 let output = xlcat() 244 .arg(path.to_str().unwrap()) 245 .arg("--max-size") 246 .arg("1K") 247 .arg("--all") 248 .assert() 249 .success(); 250 251 let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap(); 252 assert!(!stdout.contains("Large file")); 253 } 254 255 #[test] 256 fn test_empty_data_headers_only() { 257 let dir = TempDir::new().unwrap(); 258 let path = dir.path().join("empty_data.xlsx"); 259 common::create_empty_data(&path); 260 261 xlcat() 262 .arg(path.to_str().unwrap()) 263 .assert() 264 .success() 265 .stdout(predicate::str::contains("no data rows")); 266 } 267 268 #[test] 269 fn test_head_and_tail_together() { 270 let dir = TempDir::new().unwrap(); 271 let path = dir.path().join("many.xlsx"); 272 common::create_many_rows(&path); 273 274 xlcat() 275 .arg(path.to_str().unwrap()) 276 .arg("--head") 277 .arg("3") 278 .arg("--tail") 279 .arg("2") 280 .assert() 281 .success() 282 .stdout(predicate::str::contains("omitted")); 283 } 284 285 #[test] 286 fn test_tail_flag_alone() { 287 let dir = TempDir::new().unwrap(); 288 let path = dir.path().join("many.xlsx"); 289 common::create_many_rows(&path); 290 291 let output = xlcat() 292 .arg(path.to_str().unwrap()) 293 .arg("--tail") 294 .arg("3") 295 .assert() 296 .success(); 297 298 let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap(); 299 assert!(!stdout.contains("omitted")); 300 // Should contain the last rows (ids near 80) 301 assert!(stdout.contains("80")); 302 } 303 304 #[test] 305 fn test_csv_respects_head() { 306 let dir = TempDir::new().unwrap(); 307 let path = dir.path().join("many.xlsx"); 308 common::create_many_rows(&path); 309 310 let output = xlcat() 311 .arg(path.to_str().unwrap()) 312 .arg("--csv") 313 .arg("--head") 314 .arg("3") 315 .assert() 316 .success(); 317 318 let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap(); 319 // Header + 3 data rows = 4 non-empty lines 320 let lines: Vec<&str> = stdout.trim().lines().collect(); 321 assert_eq!(lines.len(), 4, "Expected header + 3 data rows, got: {}", stdout); 322 } 323 324 #[test] 325 fn test_head_tail_overlap_shows_all() { 326 let dir = TempDir::new().unwrap(); 327 let path = dir.path().join("simple.xlsx"); 328 common::create_simple(&path); 329 330 // 5 rows, head 3 + tail 3 = 6 > 5, so show all without duplication 331 let output = xlcat() 332 .arg(path.to_str().unwrap()) 333 .arg("--head") 334 .arg("3") 335 .arg("--tail") 336 .arg("3") 337 .assert() 338 .success(); 339 340 let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap(); 341 assert!(!stdout.contains("omitted")); 342 assert!(stdout.contains("Alice")); 343 assert!(stdout.contains("Eve")); 344 } 345 346 #[test] 347 fn test_wrong_extension() { 348 let dir = TempDir::new().unwrap(); 349 let path = dir.path().join("data.csv"); 350 std::fs::write(&path, "a,b\n1,2\n").unwrap(); 351 352 xlcat() 353 .arg(path.to_str().unwrap()) 354 .assert() 355 .failure() 356 .stderr(predicate::str::contains("Expected .xls or .xlsx")); 357 } 358 359 #[test] 360 fn test_sheet_not_found() { 361 let dir = TempDir::new().unwrap(); 362 let path = dir.path().join("simple.xlsx"); 363 common::create_simple(&path); 364 365 xlcat() 366 .arg(path.to_str().unwrap()) 367 .arg("--sheet") 368 .arg("Nonexistent") 369 .assert() 370 .failure() 371 .stderr(predicate::str::contains("not found")); 372 } 373 374 #[test] 375 fn test_exit_code_success() { 376 let dir = TempDir::new().unwrap(); 377 let path = dir.path().join("simple.xlsx"); 378 common::create_simple(&path); 379 380 xlcat() 381 .arg(path.to_str().unwrap()) 382 .assert() 383 .code(0); 384 } 385 386 #[test] 387 fn test_exit_code_runtime_error() { 388 xlcat() 389 .arg("/nonexistent.xlsx") 390 .assert() 391 .code(1); 392 } 393 394 #[test] 395 fn test_exit_code_invalid_args() { 396 let dir = TempDir::new().unwrap(); 397 let path = dir.path().join("simple.xlsx"); 398 common::create_simple(&path); 399 400 xlcat() 401 .arg(path.to_str().unwrap()) 402 .arg("--schema") 403 .arg("--describe") 404 .assert() 405 .code(2); 406 } 407 408 #[test] 409 fn test_describe_multi_sheet_no_sheet_flag() { 410 let dir = TempDir::new().unwrap(); 411 let path = dir.path().join("multi.xlsx"); 412 common::create_multi_sheet(&path); 413 414 xlcat() 415 .arg(path.to_str().unwrap()) 416 .arg("--describe") 417 .assert() 418 .success() 419 .stdout(predicate::str::contains("## Sheet: Revenue")) 420 .stdout(predicate::str::contains("## Sheet: Expenses")) 421 .stdout(predicate::str::contains("count")) 422 .stdout(predicate::str::contains("mean")); 423 } 424 425 #[test] 426 fn test_csv_multi_sheet_without_sheet_is_error() { 427 let dir = TempDir::new().unwrap(); 428 let path = dir.path().join("multi.xlsx"); 429 common::create_multi_sheet(&path); 430 431 xlcat() 432 .arg(path.to_str().unwrap()) 433 .arg("--csv") 434 .assert() 435 .failure() 436 .stderr(predicate::str::contains("Multiple sheets")); 437 }