Add special case for object trees.

This commit is contained in:
Tom Alexander 2023-12-29 17:46:35 -05:00
parent 78befc7665
commit 90735586b5
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
3 changed files with 113 additions and 70 deletions

View File

@ -15,8 +15,14 @@ use crate::types::AffiliatedKeywords;
pub enum AdditionalPropertyValue {
SingleString(String),
ListOfStrings(Vec<String>),
OptionalPair { optval: Option<String>, val: String },
ObjectTree(Vec<(Option<Vec<WasmAstNode>>, Vec<WasmAstNode>)>),
OptionalPair {
optval: Option<String>,
val: String,
},
ObjectTree {
#[serde(rename = "object-tree")]
object_tree: Vec<(Option<Vec<WasmAstNode>>, Vec<WasmAstNode>)>,
},
}
#[derive(Debug, Serialize, Deserialize, Default)]
@ -84,7 +90,7 @@ to_wasm!(
ret.push((converted_optval, converted_value));
}
AdditionalPropertyValue::ObjectTree(ret)
AdditionalPropertyValue::ObjectTree { object_tree: ret }
}
};
additional_properties

View File

@ -3,75 +3,13 @@ use std::collections::HashMap;
use super::diff::WasmDiffResult;
use super::diff::WasmDiffStatus;
use crate::compare::get_emacs_standard_properties;
use crate::compare::maybe_token_to_usize;
use crate::compare::unquote;
use crate::compare::ElispFact;
use crate::compare::EmacsField;
use crate::compare::EmacsStandardProperties;
use crate::compare::TextWithProperties;
use crate::compare::Token;
use crate::wasm::WasmAngleLink;
use crate::wasm::WasmAstNode;
use crate::wasm::WasmAstNodeWrapper;
use crate::wasm::WasmBabelCall;
use crate::wasm::WasmBold;
use crate::wasm::WasmCenterBlock;
use crate::wasm::WasmCitation;
use crate::wasm::WasmCitationReference;
use crate::wasm::WasmClock;
use crate::wasm::WasmCode;
use crate::wasm::WasmComment;
use crate::wasm::WasmCommentBlock;
use crate::wasm::WasmDiarySexp;
use crate::wasm::WasmDocument;
use crate::wasm::WasmDrawer;
use crate::wasm::WasmDynamicBlock;
use crate::wasm::WasmEntity;
use crate::wasm::WasmExampleBlock;
use crate::wasm::WasmExportBlock;
use crate::wasm::WasmExportSnippet;
use crate::wasm::WasmFixedWidthArea;
use crate::wasm::WasmFootnoteDefinition;
use crate::wasm::WasmFootnoteReference;
use crate::wasm::WasmHeadline;
use crate::wasm::WasmHorizontalRule;
use crate::wasm::WasmInlineBabelCall;
use crate::wasm::WasmInlineSourceBlock;
use crate::wasm::WasmItalic;
use crate::wasm::WasmKeyword;
use crate::wasm::WasmLatexEnvironment;
use crate::wasm::WasmLatexFragment;
use crate::wasm::WasmLineBreak;
use crate::wasm::WasmNodeProperty;
use crate::wasm::WasmOrgMacro;
use crate::wasm::WasmParagraph;
use crate::wasm::WasmPlainLink;
use crate::wasm::WasmPlainList;
use crate::wasm::WasmPlainListItem;
use crate::wasm::WasmPlainText;
use crate::wasm::WasmPlanning;
use crate::wasm::WasmPropertyDrawer;
use crate::wasm::WasmQuoteBlock;
use crate::wasm::WasmRadioLink;
use crate::wasm::WasmRadioTarget;
use crate::wasm::WasmRegularLink;
use crate::wasm::WasmSection;
use crate::wasm::WasmSpecialBlock;
use crate::wasm::WasmSrcBlock;
use crate::wasm::WasmStatisticsCookie;
use crate::wasm::WasmStrikeThrough;
use crate::wasm::WasmSubscript;
use crate::wasm::WasmSuperscript;
use crate::wasm::WasmTable;
use crate::wasm::WasmTableCell;
use crate::wasm::WasmTableRow;
use crate::wasm::WasmTarget;
use crate::wasm::WasmTimestamp;
use crate::wasm::WasmUnderline;
use crate::wasm::WasmVerbatim;
use crate::wasm::WasmVerseBlock;
use crate::wasm_test::macros::wasm_compare;
pub fn wasm_compare_document<'e, 's, 'w>(
source: &'s str,
@ -88,10 +26,10 @@ fn compare_json_value<'b, 's>(
emacs: &'b Token<'s>,
wasm: &serde_json::Value,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
println!("XXXXXXXXXXXXXX compare_json_value XXXXXXXXXXXXXX");
println!("{:?}", emacs);
println!("{:?}", wasm);
println!("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
// println!("XXXXXXXXXXXXXX compare_json_value XXXXXXXXXXXXXX");
// println!("{:?}", emacs);
// println!("{:?}", wasm);
// println!("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
match (wasm, emacs) {
(serde_json::Value::Object(wasm), Token::List(el)) if wasm.contains_key("ast-node") => {
// We hit a regular ast node.
@ -104,6 +42,7 @@ fn compare_json_value<'b, 's>(
compare_quoted_string(source, e, w)
}
(serde_json::Value::Array(w), Token::List(e)) => {
// TODO: This is creating children with no names.
wasm_compare_list(source, e.iter(), w.iter())
}
(serde_json::Value::Object(wasm), Token::List(e))
@ -111,6 +50,10 @@ fn compare_json_value<'b, 's>(
{
compare_optional_pair(source, e, wasm)
}
(serde_json::Value::Object(wasm), Token::List(el)) if wasm.contains_key("object-tree") => {
// We hit an object tree additional property.
compare_object_tree(source, el, wasm)
}
(serde_json::Value::Object(w), Token::TextWithProperties(e)) if is_plain_text(w) => {
compare_plain_text(source, e, w)
}
@ -494,6 +437,100 @@ fn compare_optional_pair<'e, 's, 'w>(
Ok(result)
}
fn compare_object_tree<'e, 's, 'w>(
source: &'s str,
emacs: &'e Vec<Token<'s>>,
wasm: &'w serde_json::Map<String, serde_json::Value>,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
let mut result = WasmDiffResult::default();
let wasm_attributes = wasm
.get("object-tree")
.ok_or(r#"Wasm object tree should have an "object-tree" attribute."#)?
.as_array()
.ok_or(r#"Wasm "object-tree" attribute should be a list."#)?;
let emacs_outer_length = emacs.len();
let wasm_outer_length = wasm_attributes.len();
if emacs_outer_length != wasm_outer_length {
result.status.push(WasmDiffStatus::Bad(
format!(
"Child length mismatch. Emacs=({emacs:?}) Wasm=({wasm:?}).",
emacs = emacs_outer_length,
wasm = wasm_outer_length
)
.into(),
));
return Ok(result);
}
for (emacs_attribute, wasm_attribute) in emacs.iter().zip(wasm_attributes.iter()) {
let emacs_attribute = emacs_attribute.as_list()?;
let wasm_attribute = wasm_attribute
.as_array()
.ok_or("Wasm middle layer in object tree should be a list.")?;
if wasm_attribute.len() != 2 {
result.status.push(WasmDiffStatus::Bad(
format!(
"Wasm middle layer in object tree should have a length of 2. Wasm=({wasm:?}).",
wasm = wasm_attribute.len()
)
.into(),
));
return Ok(result);
}
if let Some(serde_json::Value::Null) = wasm_attribute.first() {
// If optval is null then the emacs array should only contain 1 value.
if emacs_attribute.len() != 1 {
result.status.push(WasmDiffStatus::Bad(
format!(
"Emacs middle layer in object tree should have a length of 1. Emacs=({emacs:?}) Wasm=({wasm:?}).",
emacs = emacs_attribute,
wasm = wasm_attribute
)
.into(),
));
return Ok(result);
}
let emacs_val = emacs_attribute
.first()
.expect("If-statement proves this will be Some.");
let wasm_val = wasm_attribute
.get(1)
.expect("If-statement proves this will be Some.");
result.extend(compare_json_value(source, emacs_val, wasm_val)?)?;
} else {
// If optval is not null, then the emacs array should contain 3 values, the optval, a dot, and the val.
if emacs_attribute.len() != 3 {
result.status.push(WasmDiffStatus::Bad(
format!(
"Emacs middle layer in object tree should have a length of 3. Emacs=({emacs:?}) Wasm=({wasm:?}).",
emacs = emacs_attribute,
wasm = wasm_attribute
)
.into(),
));
return Ok(result);
}
let emacs_optval = emacs_attribute
.first()
.expect("If-statement proves this will be Some.");
let wasm_optval = wasm_attribute
.first()
.expect("If-statement proves this will be Some.");
let emacs_val = emacs_attribute
.get(2)
.expect("If-statement proves this will be Some.");
let wasm_val = wasm_attribute
.get(1)
.expect("If-statement proves this will be Some.");
result.extend(compare_json_value(source, emacs_optval, wasm_optval)?)?;
result.extend(compare_json_value(source, emacs_val, wasm_val)?)?;
}
}
Ok(result)
}
fn is_plain_text<'e, 's, 'w>(wasm: &'w serde_json::Map<String, serde_json::Value>) -> bool {
if let Some(serde_json::Value::String(node_type)) = wasm.get("ast-node") {
node_type == "plain-text"

View File

@ -55,7 +55,7 @@ impl<'s> WasmDiffResult<'s> {
original_document: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let status_text = {
if self.is_bad() {
if self.is_self_bad() {
format!(
"{color}BAD{reset}",
color = foreground_color(255, 0, 0),