| 32 | } |
| 33 | |
| 34 | fn check(bin: &str, c: &Case) -> Result<(), String> { |
| 35 | let dir = tempfile::tempdir().map_err(|e| e.to_string())?; |
| 36 | for (p, v) in &c.given { |
| 37 | let path = dir.path().join(p); |
| 38 | if let Some(d) = path.parent() { let _ = std::fs::create_dir_all(d); } |
| 39 | std::fs::write(path, v).map_err(|e| e.to_string())?; |
| 40 | } |
| 41 | let mut child = Command::new(bin).args(&c.run).current_dir(&dir) |
| 42 | .stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()) |
| 43 | .spawn().map_err(|e| e.to_string())?; |
| 44 | if !c.stdin.is_empty() { |
| 45 | child.stdin.as_mut().unwrap().write_all(c.stdin.as_bytes()).map_err(|e| e.to_string())?; |
| 46 | } |
| 47 | drop(child.stdin.take()); // close stdin so the process sees EOF |
| 48 | let out = child.wait_with_output().map_err(|e| e.to_string())?; |
| 49 | let so = String::from_utf8_lossy(&out.stdout); |
| 50 | let se = String::from_utf8_lossy(&out.stderr); |
| 51 | let exit = out.status.code().unwrap_or(-1); |
| 52 | let want_fail = c.fails.is_some(); |
| 53 | if (exit != 0) != want_fail { |
| 54 | return Err(format!("exit {exit}; want {}; stderr: {se}", if want_fail { "non-zero" } else { "0" })); |
| 55 | } |
| 56 | for n in c.stderr.iter().chain(c.fails.iter().flatten()) { |
| 57 | if !se.contains(n.as_str()) { return Err(format!("stderr missing {n:?}; got: {se}")); } |
| 58 | } |
| 59 | for n in &c.stdout { if !so.contains(n) { return Err(format!("stdout missing {n:?}; got: {so}")); } } |
| 60 | for f in &c.creates { if !dir.path().join(f).exists() { return Err(format!("file missing: {f}")); } } |
| 61 | for (f, n) in &c.contains { |
| 62 | let t = std::fs::read_to_string(dir.path().join(f)).map_err(|e| e.to_string())?; |
| 63 | if !t.contains(n) { return Err(format!("{f} missing {n:?}; got: {t}")); } |
| 64 | } |
| 65 | Ok(()) |
| 66 | } |