mod common;
use common::drive;
mod jsonl_input {
use super::drive;
#[test]
fn groups_by_named_field_auto() {
let stdin = "{\"kind\":\"bug\"}\n{\"kind\":\"bug\"}\n{\"kind\":\"feat\"}\n";
let (code, stdout, stderr) = drive(&["face"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(
stdout.contains("bug"),
"expected `bug` cluster in stdout: {stdout:?}",
);
assert!(
stdout.contains("feat"),
"expected `feat` cluster in stdout: {stdout:?}",
);
}
#[test]
fn rg_json_auto_groups_by_nested_path() {
let stdin = "\
{\"type\":\"begin\",\"data\":{\"path\":{\"text\":\"Modules/Share/A.swift\"}}}\n\
{\"type\":\"match\",\"data\":{\"path\":{\"text\":\"Modules/Share/A.swift\"},\"lines\":{\"text\":\"let viewModel = AViewModel()\"}}}\n\
{\"type\":\"end\",\"data\":{\"path\":{\"text\":\"Modules/Share/A.swift\"}}}\n\
{\"type\":\"begin\",\"data\":{\"path\":{\"text\":\"Modules/Room/B.swift\"}}}\n\
{\"type\":\"match\",\"data\":{\"path\":{\"text\":\"Modules/Room/B.swift\"},\"lines\":{\"text\":\"let viewModel = BViewModel()\"}}}\n\
{\"type\":\"end\",\"data\":{\"path\":{\"text\":\"Modules/Room/B.swift\"}}}\n\
{\"type\":\"summary\",\"data\":{\"elapsed_total\":{\"secs\":0,\"nanos\":1}}}\n";
let (code, stdout, stderr) = drive(&["face", "--verbose"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(
stderr.contains("items by data.path.text"),
"verbose provenance names nested rg path: stderr={stderr:?}",
);
assert!(
stdout.contains("Modules/Share/A.swift") && stdout.contains("Modules/Room/B.swift"),
"stdout clusters by file path: {stdout:?}",
);
assert!(
!stdout.contains("match"),
"stdout should not cluster by rg record type: {stdout:?}",
);
}
#[test]
fn respects_format_json_flag() {
let stdin = "{\"kind\":\"bug\"}\n{\"kind\":\"bug\"}\n{\"kind\":\"feat\"}\n";
let (code, stdout, stderr) = drive(&["face", "--format=json"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
let v: serde_json::Value = serde_json::from_str(&stdout).expect("stdout is parseable JSON");
assert!(v.get("result").is_some(), "envelope has `result` key");
assert!(v.get("clusters").is_some(), "envelope has `clusters` key");
}
#[test]
fn respects_format_tsv_flag() {
let stdin = "{\"kind\":\"bug\"}\n{\"kind\":\"bug\"}\n{\"kind\":\"feat\"}\n";
let (code, stdout, stderr) = drive(&["face", "--format=tsv"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
let header = stdout.lines().next().unwrap_or("");
assert!(header.contains("id"), "tsv header has `id`: {header:?}");
assert!(
header.contains("label"),
"tsv header has `label`: {header:?}",
);
assert!(
header.contains("count"),
"tsv header has `count`: {header:?}",
);
}
#[test]
fn markdown_format() {
let stdin = "{\"kind\":\"bug\"}\n{\"kind\":\"bug\"}\n{\"kind\":\"feat\"}\n";
let (code, stdout, stderr) = drive(&["face", "--format=markdown"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(
stdout.contains("## bug"),
"markdown should include `## bug`: {stdout:?}",
);
}
}
mod json_input {
use super::drive;
#[test]
fn top_level_array() {
let stdin = "[{\"kind\":\"bug\"},{\"kind\":\"bug\"},{\"kind\":\"feat\"}]";
let (code, stdout, stderr) = drive(&["face"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(stdout.contains("bug"), "stdout contains bug: {stdout:?}");
assert!(stdout.contains("feat"), "stdout contains feat: {stdout:?}");
}
#[test]
fn large_pretty_array_past_probe() {
let stdin = format!(
"[\n {{\"kind\":\"bug\",\"text\":\"{}\"}},\n {{\"kind\":\"feat\",\"text\":\"done\"}}\n]\n",
"x".repeat(8192)
);
let (code, stdout, stderr) = drive(&["face"], &stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(stdout.contains("bug"), "stdout contains bug: {stdout:?}");
assert!(stdout.contains("feat"), "stdout contains feat: {stdout:?}");
}
#[test]
fn object_with_named_items() {
let stdin = "{\"items\":[{\"kind\":\"bug\"},{\"kind\":\"feat\"}]}";
let (code, stdout, stderr) = drive(&["face"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(stdout.contains("bug"), "stdout contains bug: {stdout:?}");
assert!(stdout.contains("feat"), "stdout contains feat: {stdout:?}");
}
}
mod delimited_input {
use super::drive;
#[test]
fn csv_with_header_groups() {
let stdin = "kind,severity\nbug,high\nbug,low\nfeat,low\n";
let (code, stdout, stderr) = drive(&["face"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(stdout.contains("bug"), "stdout contains bug: {stdout:?}");
assert!(stdout.contains("feat"), "stdout contains feat: {stdout:?}");
}
#[test]
fn csv_headerless_with_columns() {
let stdin = "bug,high\nfeat,low\n";
let (code, stdout, stderr) = drive(
&["face", "--format-in=csv", "--columns=kind,severity"],
stdin,
);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(stdout.contains("bug"), "stdout contains bug: {stdout:?}");
assert!(stdout.contains("feat"), "stdout contains feat: {stdout:?}");
}
#[test]
fn tsv_with_header_groups() {
let stdin = "kind\tseverity\nbug\thigh\nfeat\tlow\n";
let (code, stdout, stderr) = drive(&["face"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(stdout.contains("bug"), "stdout contains bug: {stdout:?}");
assert!(stdout.contains("feat"), "stdout contains feat: {stdout:?}");
}
}
mod with_score {
use super::drive;
#[test]
fn score_detected_uses_bands() {
let stdin = "{\"score\":0.9,\"name\":\"a\"}\n\
{\"score\":0.5,\"name\":\"b\"}\n\
{\"score\":0.1,\"name\":\"c\"}\n";
let (code, stdout, stderr) = drive(&["face"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(
stdout.contains('\u{2013}'),
"expected en-dash band label in stdout: {stdout:?}",
);
}
#[test]
fn explicit_score_path() {
let stdin = "{\"value\":0.9,\"name\":\"a\"}\n\
{\"value\":0.5,\"name\":\"b\"}\n\
{\"value\":0.1,\"name\":\"c\"}\n";
let (code, stdout, stderr) = drive(&["face", "--score=.value"], stdin);
assert_eq!(code, 0, "stderr={stderr:?} stdout={stdout:?}");
assert!(
stdout.contains('\u{2013}'),
"expected band label in stdout: {stdout:?}",
);
}
}