Compare commits

...

5 Commits

Author SHA1 Message Date
Tom Alexander
a5e108bc37
Compare the standard properties.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-27 17:07:42 -05:00
Tom Alexander
58290515b5
Enable child checking. 2023-12-27 16:47:02 -05:00
Tom Alexander
423f65046e
Record the property comparisons. 2023-12-27 16:40:55 -05:00
Tom Alexander
badeaf8246
Add compare for document category. 2023-12-27 16:34:04 -05:00
Tom Alexander
d38100581c
Add a script to run the wasm test inside docker. 2023-12-27 16:32:06 -05:00
11 changed files with 363 additions and 28 deletions

View File

@ -0,0 +1,111 @@
#!/usr/bin/env bash
#
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
: ${SHELL:="NO"} # or YES to launch a shell instead of running the test
: ${TRACE:="NO"} # or YES to send traces to jaeger
: ${BACKTRACE:="NO"} # or YES to print a rust backtrace when panicking
: ${NO_COLOR:=""} # Set to anything to disable color output
: ${PROFILE:="debug"}
REALPATH=$(command -v uu-realpath || command -v realpath)
MAKE=$(command -v gmake || command -v make)
############## Setup #########################
function die {
local status_code="$1"
shift
(>&2 echo "${@}")
exit "$status_code"
}
function log {
(>&2 echo "${@}")
}
############## Program #########################
function main {
build_container
launch_container "${@}"
}
function build_container {
$MAKE -C "$DIR/../docker/organic_test"
}
function launch_container {
local additional_flags=()
local features=(wasm_test)
if [ "$NO_COLOR" != "" ]; then
additional_flags+=(--env "NO_COLOR=$NO_COLOR")
fi
if [ "$TRACE" = "YES" ]; then
# We use the host network so it can talk to jaeger hosted at 127.0.0.1
additional_flags+=(--network=host --env RUST_LOG=debug)
features+=(tracing)
fi
if [ "$SHELL" != "YES" ]; then
additional_flags+=(--read-only)
else
additional_flags+=(-t)
fi
if [ "$BACKTRACE" = "YES" ]; then
additional_flags+=(--env RUST_BACKTRACE=full)
fi
if [ "$SHELL" = "YES" ]; then
exec docker run "${additional_flags[@]}" --init --rm -i --mount type=tmpfs,destination=/tmp -v "/:/input:ro" -v "$($REALPATH "$DIR/../"):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source --entrypoint "" organic-test /bin/sh
fi
local features_joined
features_joined=$(IFS=","; echo "${features[*]}")
local build_flags=()
if [ "$PROFILE" = "dev" ] || [ "$PROFILE" = "debug" ]; then
PROFILE="debug"
else
build_flags+=(--profile "$PROFILE")
fi
if [ $# -gt 0 ]; then
# If we passed in args, we need to forward them along
for path in "${@}"; do
local full_path
full_path=$($REALPATH "$path")
init_script=$(cat <<EOF
set -euo pipefail
IFS=\$'\n\t'
cargo build --bin wasm_test --no-default-features --features "$features_joined" ${build_flags[@]}
exec /target/${PROFILE}/wasm_test "/input${full_path}"
EOF
)
docker run "${additional_flags[@]}" --init --rm -i --mount type=tmpfs,destination=/tmp -v "/:/input:ro" -v "$($REALPATH "$DIR/../"):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source --entrypoint "" organic-test sh -c "$init_script"
done
else
local current_directory init_script
current_directory=$(pwd)
init_script=$(cat <<EOF
set -euo pipefail
IFS=\$'\n\t'
cargo build --bin wasm_test --no-default-features --features "$features_joined" ${build_flags[@]}
cd /input${current_directory}
exec /target/${PROFILE}/wasm_test
EOF
)
docker run "${additional_flags[@]}" --init --rm -i --mount type=tmpfs,destination=/tmp -v "/:/input:ro" -v "$($REALPATH "$DIR/../"):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source --entrypoint "" organic-test sh -c "$init_script"
fi
}
main "${@}"

View File

@ -3,6 +3,7 @@
use std::io::Read;
use organic::wasm_test::wasm_run_anonymous_compare;
use organic::wasm_test::wasm_run_compare_on_file;
#[cfg(feature = "tracing")]
use crate::init_tracing::init_telemetry;
@ -42,14 +43,13 @@ async fn main_body() -> Result<(), Box<dyn std::error::Error>> {
}
Ok(())
} else {
todo!()
// for arg in args {
// if run_compare_on_file(arg).await? {
// } else {
// Err("Diff results do not match.")?;
// }
// }
// Ok(())
for arg in args {
if wasm_run_compare_on_file(arg).await? {
} else {
Err("Diff results do not match.")?;
}
}
Ok(())
}
}

View File

@ -16,4 +16,6 @@ pub(crate) use compare_field::EmacsField;
pub(crate) use elisp_fact::ElispFact;
pub use sexp::sexp;
pub use sexp::Token;
pub(crate) use util::get_emacs_standard_properties;
pub(crate) use util::get_property_quoted_string;
pub(crate) use util::EmacsStandardProperties;

View File

@ -145,20 +145,20 @@ fn assert_post_blank<'b, 's, S: StandardProperties<'s> + ?Sized>(
Ok(())
}
struct EmacsStandardProperties {
begin: Option<usize>,
pub(crate) struct EmacsStandardProperties {
pub(crate) begin: Option<usize>,
#[allow(dead_code)]
post_affiliated: Option<usize>,
pub(crate) post_affiliated: Option<usize>,
#[allow(dead_code)]
contents_begin: Option<usize>,
pub(crate) contents_begin: Option<usize>,
#[allow(dead_code)]
contents_end: Option<usize>,
end: Option<usize>,
pub(crate) contents_end: Option<usize>,
pub(crate) end: Option<usize>,
#[allow(dead_code)]
post_blank: Option<usize>,
pub(crate) post_blank: Option<usize>,
}
fn get_emacs_standard_properties(
pub(crate) fn get_emacs_standard_properties(
emacs: &Token<'_>,
) -> Result<EmacsStandardProperties, Box<dyn std::error::Error>> {
let children = emacs.as_list()?;

View File

@ -15,10 +15,10 @@ use crate::wasm::to_wasm::ToWasmStandardProperties;
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmDocument<'s, 'p> {
standard_properties: WasmStandardProperties,
pub(crate) standard_properties: WasmStandardProperties,
additional_properties: Vec<(String, &'s str)>,
pub(crate) children: Vec<WasmAstNode<'s, 'p>>,
category: Option<&'p str>,
pub(crate) category: Option<&'p str>,
pub(crate) path: Option<PathBuf>,
}

View File

@ -64,6 +64,9 @@ mod verse_block;
pub use ast_node::WasmAstNode;
pub use document::WasmDocument;
pub(crate) use headline::WasmHeadline;
pub use parse_result::ParseResult;
pub(crate) use section::WasmSection;
pub(crate) use standard_properties::WasmStandardProperties;
pub use to_wasm::ToWasm;
pub use to_wasm::ToWasmContext;

View File

@ -7,11 +7,11 @@ use crate::types::StandardProperties;
#[derive(Debug, Serialize)]
pub(crate) struct WasmStandardProperties {
begin: usize,
end: usize,
contents_begin: Option<usize>,
contents_end: Option<usize>,
post_blank: PostBlank,
pub(crate) begin: usize,
pub(crate) end: usize,
pub(crate) contents_begin: Option<usize>,
pub(crate) contents_end: Option<usize>,
pub(crate) post_blank: PostBlank,
}
impl<'s, SP: StandardProperties<'s>> ToWasmStandardProperties for SP {

View File

@ -1,12 +1,16 @@
use std::borrow::Cow;
use super::elisp_compare::WasmElispCompare;
use crate::compare::get_emacs_standard_properties;
use crate::compare::get_property_quoted_string;
use crate::compare::ElispFact;
use crate::compare::EmacsField;
use crate::compare::Token;
use crate::wasm::WasmAstNode;
use crate::wasm::WasmDocument;
use crate::wasm::WasmHeadline;
use crate::wasm::WasmSection;
use crate::wasm::WasmStandardProperties;
use crate::wasm_test::macros::wasm_compare;
pub fn wasm_compare_document<'b, 's, 'p>(
@ -172,8 +176,8 @@ impl<'s, 'p> WasmElispCompare<'s, 'p> for WasmAstNode<'s, 'p> {
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
match self {
WasmAstNode::Document(inner) => inner.compare_ast_node(source, emacs),
WasmAstNode::Headline(_) => todo!(),
WasmAstNode::Section(_) => todo!(),
WasmAstNode::Headline(inner) => inner.compare_ast_node(source, emacs),
WasmAstNode::Section(inner) => inner.compare_ast_node(source, emacs),
WasmAstNode::Paragraph(_) => todo!(),
WasmAstNode::PlainList(_) => todo!(),
WasmAstNode::PlainListItem(_) => todo!(),
@ -247,12 +251,71 @@ impl<'s, 'p> WasmElispCompare<'s, 'p> for WasmDocument<'s, 'p> {
EmacsField::Required(":path"),
|w| w.path.as_ref().and_then(|p| p.to_str()),
wasm_compare_property_quoted_string
),
(
EmacsField::Required(":CATEGORY"),
|w| w.category.as_ref(),
wasm_compare_property_quoted_string
)
);
Ok(result)
}
}
impl<'s, 'p> WasmElispCompare<'s, 'p> for WasmHeadline<'s, 'p> {
fn compare_ast_node<'b>(
&self,
source: &'s str,
emacs: &'b Token<'s>,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
let result = WasmDiffResult::default();
// let result = wasm_compare!(
// source,
// emacs,
// self,
// (
// EmacsField::Required(":path"),
// |w| w.path.as_ref().and_then(|p| p.to_str()),
// wasm_compare_property_quoted_string
// ),
// (
// EmacsField::Required(":CATEGORY"),
// |w| w.category.as_ref(),
// wasm_compare_property_quoted_string
// )
// );
Ok(result)
}
}
impl<'s, 'p> WasmElispCompare<'s, 'p> for WasmSection<'s, 'p> {
fn compare_ast_node<'b>(
&self,
source: &'s str,
emacs: &'b Token<'s>,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
let result = WasmDiffResult::default();
// let result = wasm_compare!(
// source,
// emacs,
// self,
// (
// EmacsField::Required(":path"),
// |w| w.path.as_ref().and_then(|p| p.to_str()),
// wasm_compare_property_quoted_string
// ),
// (
// EmacsField::Required(":CATEGORY"),
// |w| w.category.as_ref(),
// wasm_compare_property_quoted_string
// )
// );
Ok(result)
}
}
fn wasm_compare_property_quoted_string<
'b,
's,
@ -282,3 +345,74 @@ fn wasm_compare_property_quoted_string<
}
Ok(result)
}
fn wasm_compare_standard_properties<'b, 's>(
_source: &'s str,
emacs: &'b Token<'s>,
wasm: &WasmStandardProperties,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
let mut result = WasmDiffResult::default();
let mut layer = WasmDiffResult::default();
layer.name = "standard-properties".into();
let standard_properties = get_emacs_standard_properties(emacs)?;
if Some(wasm.begin) != standard_properties.begin {
layer.status.push(WasmDiffStatus::Bad(
format!(
"Property mismatch. Property=({property}) Emacs=({emacs:?}) Wasm=({wasm:?}).",
property = "begin",
emacs = standard_properties.begin,
wasm = Some(wasm.begin),
)
.into(),
));
}
if Some(wasm.end) != standard_properties.end {
layer.status.push(WasmDiffStatus::Bad(
format!(
"Property mismatch. Property=({property}) Emacs=({emacs:?}) Wasm=({wasm:?}).",
property = "end",
emacs = standard_properties.end,
wasm = Some(wasm.end),
)
.into(),
));
}
if wasm.contents_begin != standard_properties.contents_begin {
layer.status.push(WasmDiffStatus::Bad(
format!(
"Property mismatch. Property=({property}) Emacs=({emacs:?}) Wasm=({wasm:?}).",
property = "contents-begin",
emacs = standard_properties.contents_begin,
wasm = wasm.contents_begin,
)
.into(),
));
}
if wasm.contents_end != standard_properties.contents_end {
layer.status.push(WasmDiffStatus::Bad(
format!(
"Property mismatch. Property=({property}) Emacs=({emacs:?}) Wasm=({wasm:?}).",
property = "contents-end",
emacs = standard_properties.contents_end,
wasm = wasm.contents_end,
)
.into(),
));
}
if Some(wasm.post_blank).map(|post_blank| post_blank as usize) != standard_properties.post_blank
{
layer.status.push(WasmDiffStatus::Bad(
format!(
"Property mismatch. Property=({property}) Emacs=({emacs:?}) Wasm=({wasm:?}).",
property = "post-blank",
emacs = standard_properties.post_blank,
wasm = Some(wasm.post_blank),
)
.into(),
));
}
result.children.push(layer);
Ok(result)
}

View File

@ -12,7 +12,16 @@ macro_rules! wasm_compare {
.ok_or("Should have an attributes child.")?
.as_map()?;
let mut emacs_keys: std::collections::BTreeSet<&str> =
emacs_attributes_map.keys().map(|s| *s).collect();
emacs_attributes_map.keys().map(|s| *s).collect();
// Mark :standard-properties as seen because it will be handled separately.
if emacs_keys.contains(":standard-properties") {
emacs_keys.remove(":standard-properties");
} else {
result.status.push(WasmDiffStatus::Bad(
"Emacs node lacked :standard-properties field.".into(),
));
}
{
// Compare name.
@ -30,6 +39,11 @@ macro_rules! wasm_compare {
}
}
{
// Compare standard properties
result.extend(wasm_compare_standard_properties($source, $emacs, &$wasm.standard_properties)?)?;
}
{
// Compare children.
result.extend(wasm_compare_list(
@ -90,8 +104,7 @@ macro_rules! wasm_compare {
name
},
};
let result = $compare_fn($source, $emacs, $wasm, emacs_name, $wasm_value_getter)?;
// TODO: record this result.
result.extend($compare_fn($source, $emacs, $wasm, emacs_name, $wasm_value_getter)?)?;
)*
}

View File

@ -5,3 +5,5 @@ mod runner;
pub use runner::wasm_run_anonymous_compare;
pub use runner::wasm_run_anonymous_compare_with_settings;
pub use runner::wasm_run_compare_on_file;
pub use runner::wasm_run_compare_on_file_with_settings;

View File

@ -1,8 +1,13 @@
use std::path::Path;
use super::compare::wasm_compare_document;
use crate::compare::sexp;
use crate::context::GlobalSettings;
use crate::parser::parse_file_with_settings;
use crate::parser::parse_with_settings;
use crate::settings::LocalFileAccessInterface;
use crate::util::emacs_parse_anonymous_org_document;
use crate::util::emacs_parse_file_org_document;
use crate::util::foreground_color;
use crate::util::print_versions;
use crate::util::reset_color;
@ -59,3 +64,68 @@ pub async fn wasm_run_anonymous_compare_with_settings<'g, 's, P: AsRef<str>>(
Ok(true)
}
//wasm_run_compare_on_file
pub async fn wasm_run_compare_on_file<P: AsRef<Path>>(
org_path: P,
) -> Result<bool, Box<dyn std::error::Error>> {
wasm_run_compare_on_file_with_settings(org_path, &GlobalSettings::default(), false).await
}
pub async fn wasm_run_compare_on_file_with_settings<'g, 's, P: AsRef<Path>>(
org_path: P,
global_settings: &GlobalSettings<'g, 's>,
silent: bool,
) -> Result<bool, Box<dyn std::error::Error>> {
let org_path = org_path.as_ref();
if !silent {
print_versions().await?;
}
let parent_directory = org_path
.parent()
.ok_or("Should be contained inside a directory.")?;
let org_contents = std::fs::read_to_string(org_path)?;
// TODO: This is a work-around to pretend that dos line endings do not exist. It would be better to handle the difference in line endings.
let org_contents = org_contents.replace("\r\n", "\n");
let org_contents = org_contents.as_str();
let file_access_interface = LocalFileAccessInterface {
working_directory: Some(parent_directory.to_path_buf()),
};
let global_settings = {
let mut global_settings = global_settings.clone();
global_settings.file_access = &file_access_interface;
global_settings
};
let rust_parsed = parse_file_with_settings(org_contents, &global_settings, Some(org_path))?;
let to_wasm_context = ToWasmContext::new(org_contents);
let wasm_parsed = rust_parsed
.to_wasm(to_wasm_context)
.map_err(|_e| "Failed to convert to wasm.")?;
let org_sexp = emacs_parse_file_org_document(org_path, &global_settings).await?;
let (_remaining, parsed_sexp) = sexp(org_sexp.as_str()).map_err(|e| e.to_string())?;
if !silent {
println!("{}\n\n\n", org_contents);
println!("{}", org_sexp);
println!("{:#?}", rust_parsed);
println!("{}", serde_json::to_string(&wasm_parsed)?);
}
// We do the diffing after printing out both parsed forms in case the diffing panics
let diff_result = wasm_compare_document(org_contents, &parsed_sexp, wasm_parsed)?;
if !silent {
diff_result.print(org_contents)?;
}
if diff_result.is_bad() {
return Ok(false);
} else if !silent {
println!(
"{color}Entire document passes.{reset}",
color = foreground_color(0, 255, 0),
reset = reset_color(),
);
}
Ok(true)
}