varar_core/doc_string_diff.rs
1//! Doc-string comparison — port of `doc-string-diff.ts` / `DocStringDiff.java`.
2
3use crate::cell_diff::CellDiff;
4use crate::error::{StepError, quote};
5use crate::span::Span;
6use crate::value::Value;
7
8/// The column label a doc-string cell carries in a [`CellDiff`], so its mismatch
9/// message reads `doc string: expected … but was …`.
10pub const DOC_STRING_COLUMN: &str = "doc string";
11
12/// Compares a doc-string step's return against the fence body (exact equality,
13/// trailing newline included).
14///
15/// A doc string is ONE CELL, compared whole, so a difference is an ordinary
16/// [`CellDiff`] and the executor raises the same [`StepError::CellMismatch`] as
17/// any other cell. `expected`/`actual` are quoted: a doc string routinely
18/// differs only in whitespace, and bare text would render a missing trailing
19/// newline as no difference at all.
20///
21/// `None` → no check. A non-string return → [`StepError::ReturnShape`].
22pub fn compare_doc_string(
23 returned: Option<&Value>,
24 content: &str,
25 span: Span,
26) -> Result<Option<CellDiff>, StepError> {
27 let s = match returned {
28 None => return Ok(None),
29 Some(Value::String(s)) => s,
30 Some(other) => {
31 return Err(StepError::ReturnShape(format!(
32 "expected a doc string (string), got {}",
33 other.type_name()
34 )));
35 }
36 };
37 if s == content {
38 Ok(None)
39 } else {
40 Ok(Some(CellDiff {
41 column: DOC_STRING_COLUMN.to_string(),
42 span,
43 expected: quote(content),
44 actual: quote(s),
45 ok: false,
46 expected_value: None,
47 actual_value: None,
48 formatted: false,
49 }))
50 }
51}