use std::path::PathBuf;
use std::process::Command;
mod common;
use common::{bin_path, workspace_root};
fn fence_after(doc: &str, heading: &str) -> String {
let mut lines = doc.lines();
lines
.by_ref()
.find(|l| l.trim() == heading)
.unwrap_or_else(|| panic!("`{heading}` is not a heading in docs/technical-design.md"));
let mut opened = false;
let mut body = String::new();
for line in lines.by_ref() {
if !opened {
if line.trim_end() == "```praxis" {
opened = true;
}
continue;
}
if line.trim_end() == "```" {
return body;
}
body.push_str(line);
body.push('\n');
}
panic!("no closing ```praxis fence after `{heading}`");
}
fn codes(text: &str) -> Vec<String> {
text.lines()
.filter_map(|l| {
let rest = l.strip_prefix("error[")?;
let code = rest.split(']').next()?;
Some(code.to_string())
})
.collect()
}
#[test]
fn section_4_9s_function_example_checks_and_runs() {
let root = workspace_root();
let doc = std::fs::read_to_string(root.join("docs/technical-design.md"))
.expect("docs/technical-design.md under the workspace root");
let fence = fence_after(&doc, "### 4.9 Functions");
assert!(
fence.contains("fn manhattan(a, b)") && fence.contains("a.x"),
"extracted the wrong fence from §4.9:\n{fence}"
);
let path = PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("design_doc_section_4_9.px");
std::fs::write(&path, &fence).expect("write the extracted fence");
for command in ["check", "run"] {
let out = Command::new(bin_path())
.arg(command)
.arg(&path)
.output()
.expect("failed to run praxis");
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
codes(&stderr).is_empty(),
"`praxis {command}` on §4.9's own fence must report no diagnostic, got:\n{stderr}\
\n--- the fence ---\n{fence}"
);
}
}
#[test]
fn section_7_7s_repeated_labeled_blocks_example_runs() {
let root = workspace_root();
let doc = std::fs::read_to_string(root.join("docs/technical-design.md"))
.expect("docs/technical-design.md under the workspace root");
let fence = fence_after(&doc, "### 7.7 Repeated labeled blocks");
assert!(
fence.contains("{items:csv(int)}") && fence.contains("Monkey {id:int}:"),
"extracted the wrong fence from §7.7:\n{fence}"
);
let tmp = PathBuf::from(env!("CARGO_TARGET_TMPDIR"));
let px = tmp.join("design_doc_section_7_7.px");
std::fs::write(&px, &fence).expect("write the extracted fence");
let input = tmp.join("design_doc_section_7_7.in");
std::fs::write(
&input,
"Monkey 0:\n Starting items: 79, 98\n Operation: new = old * 19\n \
Test: divisible by 23\n If true: throw to monkey 2\n \
If false: throw to monkey 3\n\nMonkey 1:\n Starting items: 54, 65, 75, 74\n \
Operation: new = old + 6\n Test: divisible by 19\n \
If true: throw to monkey 2\n If false: throw to monkey 0\n",
)
.expect("write the sample input");
let out = Command::new(bin_path())
.arg("check")
.arg(&px)
.output()
.expect("failed to run praxis");
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
codes(&stderr).is_empty(),
"`praxis check` on §7.7's own fence must report no diagnostic, got:\n{stderr}\
\n--- the fence ---\n{fence}"
);
let out = Command::new(bin_path())
.arg("run")
.arg(&px)
.arg("--input")
.arg(&input)
.output()
.expect("failed to run praxis");
let stderr = String::from_utf8_lossy(&out.stderr);
assert_eq!(
out.status.code(),
Some(0),
"§7.7's own fence must run against the input it describes, got:\n{stderr}\
\n--- the fence ---\n{fence}"
);
}
#[test]
fn every_praxis_fence_in_the_design_doc_parses() {
let root = workspace_root();
let doc = std::fs::read_to_string(root.join("docs/technical-design.md"))
.expect("docs/technical-design.md under the workspace root");
let tmp = PathBuf::from(env!("CARGO_TARGET_TMPDIR"));
let mut fences = 0;
let mut failures = Vec::new();
let mut lines = doc.lines().enumerate();
while let Some((i, line)) = lines.next() {
if line.trim_end() != "```praxis" {
continue;
}
let mut body = String::new();
for (_, inner) in lines.by_ref() {
if inner.trim_end() == "```" {
break;
}
body.push_str(inner);
body.push('\n');
}
fences += 1;
let path = tmp.join(format!("design_doc_fence_{}.px", i + 1));
std::fs::write(&path, &body).expect("write the extracted fence");
let out = Command::new(bin_path())
.arg("check")
.arg(&path)
.output()
.expect("failed to run praxis");
let stderr = String::from_utf8_lossy(&out.stderr);
let parse_errors: Vec<_> = codes(&stderr)
.into_iter()
.filter(|c| c.starts_with('P'))
.collect();
if !parse_errors.is_empty() {
failures.push(format!(
"docs/technical-design.md:{}: {parse_errors:?}\n{body}",
i + 1
));
}
}
assert!(
fences >= 57,
"expected the design doc's ```praxis fences, found {fences}"
);
assert!(
failures.is_empty(),
"{} of {fences} fences do not parse:\n\n{}",
failures.len(),
failures.join("\n")
);
}
#[test]
fn appendix_ds_demo_checks_runs_and_prints_its_answer() {
let root = workspace_root();
let doc = std::fs::read_to_string(root.join("docs/technical-design.md"))
.expect("docs/technical-design.md under the workspace root");
let fence = fence_after(&doc, "## Appendix D: First end-to-end demo target");
assert!(
fence.contains(".sorted()") && fence.contains(".frequencies()"),
"extracted the wrong fence from Appendix D:\n{fence}"
);
let tmp = PathBuf::from(env!("CARGO_TARGET_TMPDIR"));
let px = tmp.join("design_doc_appendix_d.px");
std::fs::write(&px, &fence).expect("write the extracted fence");
let input = tmp.join("design_doc_appendix_d.in");
std::fs::write(&input, "3 4\n4 3\n2 5\n1 3\n3 9\n3 3\n")
.expect("write the sample input");
let out = Command::new(bin_path())
.arg("check")
.arg(&px)
.output()
.expect("failed to run praxis");
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
codes(&stderr).is_empty(),
"`praxis check` on Appendix D's own fence must report no diagnostic, got:\n{stderr}\
\n--- the fence ---\n{fence}"
);
let out = Command::new(bin_path())
.arg("run")
.arg(&px)
.arg("--input")
.arg(&input)
.output()
.expect("failed to run praxis");
let stderr = String::from_utf8_lossy(&out.stderr);
let stdout = String::from_utf8_lossy(&out.stdout);
assert_eq!(
out.status.code(),
Some(0),
"Appendix D must run against the input it is a demo of, got:\n{stderr}"
);
assert_eq!(stdout.trim(), "11\n31", "stderr:\n{stderr}");
}
#[test]
fn check_and_run_agree_about_a_method_that_cannot_resolve() {
let tmp = PathBuf::from(env!("CARGO_TARGET_TMPDIR"));
for (label, src) in [
("concrete", "var v = Vec[Int]()\nv.push(1)\nout(v.nope())\n"),
("pinned", "fn f(x) { x.nope() }\nout(f(3))\n"),
("never_pinned", "fn f(x) { x.nope() }\nout(1)\n"),
] {
let px = tmp.join(format!("divergence_{label}.px"));
std::fs::write(&px, src).expect("write the program");
let mut seen: Vec<String> = Vec::new();
for command in ["check", "run"] {
let out = Command::new(bin_path())
.arg(command)
.arg(&px)
.output()
.expect("failed to run praxis");
let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
assert_eq!(
codes(&stderr),
vec!["Y110".to_string()],
"`praxis {command}` on {label}:\n{src}\n{stderr}"
);
assert_eq!(out.status.code(), Some(1), "{label} / {command}");
seen.push(stderr);
}
assert_eq!(
seen[0], seen[1],
"{label}: the two commands must say it identically"
);
}
}