diff --git a/src/wasm/additional_property.rs b/src/wasm/additional_property.rs index 05845450..b754f149 100644 --- a/src/wasm/additional_property.rs +++ b/src/wasm/additional_property.rs @@ -15,8 +15,14 @@ use crate::types::AffiliatedKeywords; pub enum AdditionalPropertyValue { SingleString(String), ListOfStrings(Vec), - OptionalPair { optval: Option, val: String }, - ObjectTree(Vec<(Option>, Vec)>), + OptionalPair { + optval: Option, + val: String, + }, + ObjectTree { + #[serde(rename = "object-tree")] + object_tree: Vec<(Option>, Vec)>, + }, } #[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 diff --git a/src/wasm_test/compare.rs b/src/wasm_test/compare.rs index 45b7f161..6169f75f 100644 --- a/src/wasm_test/compare.rs +++ b/src/wasm_test/compare.rs @@ -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, Box> { - 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>, + wasm: &'w serde_json::Map, +) -> Result, Box> { + 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) -> bool { if let Some(serde_json::Value::String(node_type)) = wasm.get("ast-node") { node_type == "plain-text" diff --git a/src/wasm_test/diff.rs b/src/wasm_test/diff.rs index 0cccf4d5..7101a9db 100644 --- a/src/wasm_test/diff.rs +++ b/src/wasm_test/diff.rs @@ -55,7 +55,7 @@ impl<'s> WasmDiffResult<'s> { original_document: &str, ) -> Result<(), Box> { let status_text = { - if self.is_bad() { + if self.is_self_bad() { format!( "{color}BAD{reset}", color = foreground_color(255, 0, 0),