//! The station end to end: scripted answers on stdin, the simulated //! instrument, a throwaway comparison-data repository. use std::io::Write; use std::path::Path; use std::process::{Command, Stdio}; fn git(dir: &Path, args: &[&str]) -> String { let o = Command::new("git") .arg("-C") .arg(dir) .args(args) .output() .unwrap(); assert!( o.status.success(), "git {args:?}: {}", String::from_utf8_lossy(&o.stderr) ); String::from_utf8_lossy(&o.stdout).to_string() } /// A valid EAN-13 with the given 12 leading digits. fn ean(d12: &str) -> String { let sum: u32 = d12 .chars() .enumerate() .map(|(i, c)| c.to_digit(10).unwrap() * if i % 2 == 1 { 3 } else { 1 }) .sum(); format!("{d12}{}", (10 - sum % 10) % 10) } #[test] fn station_measures_commits_and_re_measures() { let tmp = std::env::temp_dir().join(format!("lampbench-station-{}", std::process::id())); let _ = std::fs::remove_dir_all(&tmp); let repo = tmp.join("comparison-data"); std::fs::create_dir_all(repo.join("lamps")).unwrap(); git(&repo, &["init", "-q"]); git(&repo, &["config", "user.name", "Test"]); git(&repo, &["config", "user.email", "test@example.com"]); std::fs::write(repo.join("README.md"), "data\n").unwrap(); git(&repo, &["add", "."]); git(&repo, &["commit", "-qm", "init"]); // --interval 0.5 keeps the runs in different seconds, so the re-measure changes measured_at let internal = ean("200123456789"); let answers = [ // lamp 1: no barcode "", "philips", // manufacturer -> canonical "Philips" "Test A60", // model "", // type: led "y", // dimmable "Warm White", // variant -> lower case "", // notes "806", "2700", "8.5", "", "", "60", // rated: flux, CCT, W, Ra, lifetime, equivalent "", // insert the lamp // lamp 2: retailer-internal EAN (no online lookup) &internal, "", "Shop bulb", "", "", "", "", "", "", "", "", "", "", "", // re-measure lamp 1, everything pre-filled "L0001", "", "", "", "", "", "", "", "", "", "", "", "", "", // a bad barcode, then quit "12345", "q", ] .join("\n") + "\n"; let mut child = Command::new(env!("CARGO_BIN_EXE_lampbench")) .args([ "station", "--simulate", "--settle", "0", "--readings", "2", "--interval", "0.5", "--no-push", "--no-labels", "--no-lookup", ]) .arg("--data-repo") .arg(&repo) .arg("--cache") .arg(tmp.join("ean-cache.json")) .env_remove("HPCS_LABEL_PRINTER") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() .unwrap(); child .stdin .take() .unwrap() .write_all(answers.as_bytes()) .unwrap(); let out = child.wait_with_output().unwrap(); let text = String::from_utf8_lossy(&out.stdout); assert!( out.status.success(), "{text}\n{}", String::from_utf8_lossy(&out.stderr) ); assert!(text.contains("--- New lamp L0001 ---"), "{text}"); assert!( text.contains("Using canonical brand name: Philips") || text.contains("Manufacturer"), "{text}" ); assert!( text.contains("Lookup: ? / ? (retailer-internal barcode, not resolvable)"), "{text}" ); assert!(text.contains("Re-measuring L0001"), "{text}"); assert!(text.contains("Not a valid EAN-13/UPC-A: '12345'"), "{text}"); assert!(text.contains("PSU off"), "{text}"); assert!(text.trim_end().ends_with("Bye."), "{text}"); let m: serde_json::Value = serde_json::from_str( &std::fs::read_to_string(repo.join("lamps/L0001/metrics.json")).unwrap(), ) .unwrap(); assert_eq!(m["manufacturer"], "Philips"); assert_eq!(m["variant"], "warm white"); assert_eq!(m["dimmable"], true); assert_eq!(m["type"], "led"); assert_eq!( m["rated"], serde_json::json!({"Phi_lm": 806, "CCT_K": 2700, "Power_W": 8.5, "W_equiv": 60}) ); assert_eq!(m["readings_averaged"], 2); assert_eq!(m["supply"]["ac_voltage"], 230.0); let m2: serde_json::Value = serde_json::from_str( &std::fs::read_to_string(repo.join("lamps/L0002/metrics.json")).unwrap(), ) .unwrap(); assert_eq!(m2["ean"], internal.as_str()); assert_eq!(m2["notes"], "retailer-internal barcode, brand unknown"); assert_eq!( std::fs::read_to_string(repo.join("lamps/L0001/spd.csv")) .unwrap() .lines() .count(), 351 ); assert_eq!( std::fs::read_to_string(repo.join("lamps/L0001/tm30.csv")) .unwrap() .lines() .count(), 17 ); let log = git(&repo, &["log", "--format=%s"]); let subjects: Vec<&str> = log.lines().collect(); assert_eq!( subjects[0], "Re-measure lamp L0001 (Philips, Test A60, warm white)", "{log}" ); assert_eq!( subjects[1], format!("Add lamp L0002 (Shop bulb, EAN {internal})"), "{log}" ); assert_eq!( subjects[2], "Add lamp L0001 (Philips, Test A60, warm white)", "{log}" ); let _ = std::fs::remove_dir_all(&tmp); }