Merge branch 'test_combinations'
This commit is contained in:
commit
13697df7ea
27
build.rs
27
build.rs
@ -19,8 +19,6 @@ fn main() {
|
||||
// Re-generate the tests if any org-mode files change
|
||||
println!("cargo:rerun-if-changed=org_mode_samples");
|
||||
|
||||
write_header(&mut test_file);
|
||||
|
||||
let test_files = WalkDir::new("org_mode_samples")
|
||||
.into_iter()
|
||||
.filter(|e| match e {
|
||||
@ -54,28 +52,15 @@ fn write_test(test_file: &mut File, test: &walkdir::DirEntry) {
|
||||
.strip_suffix(".org")
|
||||
.expect("Should have .org extension")
|
||||
.replace("/", "_");
|
||||
let test_name = format!("autogen_{}", test_name);
|
||||
|
||||
if let Some(_reason) = is_expect_fail(test_name.as_str()) {
|
||||
write!(test_file, "#[ignore]\n").unwrap();
|
||||
}
|
||||
write!(
|
||||
test_file,
|
||||
include_str!("./tests/test_template"),
|
||||
name = test_name,
|
||||
path = test.path().display()
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "compare")]
|
||||
fn write_header(test_file: &mut File) {
|
||||
write!(
|
||||
test_file,
|
||||
r#"
|
||||
#[feature(exit_status_error)]
|
||||
|
||||
"#
|
||||
path = test.path().display(),
|
||||
expect_fail = is_expect_fail(test_name.as_str())
|
||||
.map(|_| "#[ignore]\n")
|
||||
.unwrap_or("")
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@ -83,8 +68,8 @@ fn write_header(test_file: &mut File) {
|
||||
#[cfg(feature = "compare")]
|
||||
fn is_expect_fail(name: &str) -> Option<&str> {
|
||||
match name {
|
||||
"autogen_greater_element_drawer_drawer_with_headline_inside" => Some("Apparently lines with :end: become their own paragraph. This odd behavior needs to be investigated more."),
|
||||
"autogen_element_container_priority_footnote_definition_dynamic_block" => Some("Apparently broken begin lines become their own paragraph."),
|
||||
"greater_element_drawer_drawer_with_headline_inside" => Some("Apparently lines with :end: become their own paragraph. This odd behavior needs to be investigated more."),
|
||||
"element_container_priority_footnote_definition_dynamic_block" => Some("Apparently broken begin lines become their own paragraph."),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
7
notes/test_names.org
Normal file
7
notes/test_names.org
Normal file
@ -0,0 +1,7 @@
|
||||
* Autogen tests
|
||||
The autogen tests are the tests automatically generated to compare the output of Organic vs the upstream Emacs Org-mode parser using the sample documents in the =org_mode_samples= folder. They will have a prefix based on the settings for each test.
|
||||
|
||||
- default :: The test is run with the default settings (The upstream Emacs Org-mode determines the default settings)
|
||||
- la :: Short for "list alphabetic". Enables alphabetic plain lists.
|
||||
- t# :: Sets the tab-width to # (as in t4 sets the tab-width to 4).
|
||||
- odd :: Sets the org-odd-levels-only setting to true (meaning "odd" as opposed to "oddeven").
|
@ -0,0 +1,22 @@
|
||||
# An ordered list starting at 3
|
||||
1. [@3] foo
|
||||
|
||||
|
||||
# An ordered list starting at 11
|
||||
1. [@D] bar
|
||||
|
||||
|
||||
# An ordered list starting at 1 with the contents of "[@kk] baz"
|
||||
1. [@kk] baz
|
||||
|
||||
|
||||
# A paragraph when org-list-allow-alphabetical is nil
|
||||
m. lorem
|
||||
|
||||
|
||||
# A paragraph when org-list-allow-alphabetical is nil
|
||||
m. [@k] ipsum
|
||||
|
||||
|
||||
# An unordered list with :counter set to 3
|
||||
- [@3] dolar
|
@ -0,0 +1,30 @@
|
||||
# Alphabetic lists larger than 26 elements should become numbered. From M-x describe-variable org-list-allow-alphabetical:
|
||||
#
|
||||
# > Lists with more than 26 items will fallback to standard numbering.
|
||||
a. 1
|
||||
a. 2
|
||||
a. 3
|
||||
a. 4
|
||||
a. 5
|
||||
a. 6
|
||||
a. 7
|
||||
a. 8
|
||||
a. 9
|
||||
a. 10
|
||||
a. 11
|
||||
a. 12
|
||||
a. 13
|
||||
a. 14
|
||||
a. 15
|
||||
a. 16
|
||||
a. 17
|
||||
a. 18
|
||||
a. 19
|
||||
a. 20
|
||||
a. 21
|
||||
a. 22
|
||||
a. 23
|
||||
a. 24
|
||||
a. 25
|
||||
a. 26
|
||||
a. 27
|
@ -0,0 +1,5 @@
|
||||
# "lorem" is prefixed by a tab instead of spaces, so the editor's tab-width value determines whether lorem is a sibling of baz (tab-width 8), a sibling of bar (tab-width < 8), or a child of baz (tab-width > 8).
|
||||
1. foo
|
||||
1. bar
|
||||
1. baz
|
||||
1. lorem
|
@ -6,21 +6,31 @@ use crate::compare::parse::emacs_parse_file_org_document;
|
||||
use crate::compare::parse::get_emacs_version;
|
||||
use crate::compare::parse::get_org_mode_version;
|
||||
use crate::compare::sexp::sexp;
|
||||
use crate::parser::parse;
|
||||
use crate::context::GlobalSettings;
|
||||
use crate::context::LocalFileAccessInterface;
|
||||
use crate::parser::parse_with_settings;
|
||||
use crate::GlobalSettings;
|
||||
use crate::LocalFileAccessInterface;
|
||||
|
||||
pub fn run_anonymous_compare<P: AsRef<str>>(
|
||||
org_contents: P,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
run_anonymous_compare_with_settings(org_contents, &GlobalSettings::default())
|
||||
}
|
||||
|
||||
pub fn run_compare_on_file<P: AsRef<Path>>(org_path: P) -> Result<(), Box<dyn std::error::Error>> {
|
||||
run_compare_on_file_with_settings(org_path, &GlobalSettings::default())
|
||||
}
|
||||
|
||||
pub fn run_anonymous_compare_with_settings<P: AsRef<str>>(
|
||||
org_contents: P,
|
||||
global_settings: &GlobalSettings,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// 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.as_ref().replace("\r\n", "\n");
|
||||
let org_contents = org_contents.as_str();
|
||||
eprintln!("Using emacs version: {}", get_emacs_version()?.trim());
|
||||
eprintln!("Using org-mode version: {}", get_org_mode_version()?.trim());
|
||||
let rust_parsed = parse(org_contents)?;
|
||||
let org_sexp = emacs_parse_anonymous_org_document(org_contents)?;
|
||||
let rust_parsed = parse_with_settings(org_contents, global_settings)?;
|
||||
let org_sexp = emacs_parse_anonymous_org_document(org_contents, global_settings)?;
|
||||
let (_remaining, parsed_sexp) = sexp(org_sexp.as_str()).map_err(|e| e.to_string())?;
|
||||
|
||||
println!("{}\n\n\n", org_contents);
|
||||
@ -38,7 +48,10 @@ pub fn run_anonymous_compare<P: AsRef<str>>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_compare_on_file<P: AsRef<Path>>(org_path: P) -> Result<(), Box<dyn std::error::Error>> {
|
||||
pub fn run_compare_on_file_with_settings<P: AsRef<Path>>(
|
||||
org_path: P,
|
||||
global_settings: &GlobalSettings,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let org_path = org_path.as_ref();
|
||||
eprintln!("Using emacs version: {}", get_emacs_version()?.trim());
|
||||
eprintln!("Using org-mode version: {}", get_org_mode_version()?.trim());
|
||||
@ -53,12 +66,12 @@ pub fn run_compare_on_file<P: AsRef<Path>>(org_path: P) -> Result<(), Box<dyn st
|
||||
working_directory: Some(parent_directory.to_path_buf()),
|
||||
};
|
||||
let global_settings = {
|
||||
let mut global_settings = GlobalSettings::default();
|
||||
let mut global_settings = global_settings.clone();
|
||||
global_settings.file_access = &file_access_interface;
|
||||
global_settings
|
||||
};
|
||||
let rust_parsed = parse_with_settings(org_contents, &global_settings)?;
|
||||
let org_sexp = emacs_parse_file_org_document(org_path)?;
|
||||
let org_sexp = emacs_parse_file_org_document(org_path, &global_settings)?;
|
||||
let (_remaining, parsed_sexp) = sexp(org_sexp.as_str()).map_err(|e| e.to_string())?;
|
||||
|
||||
println!("{}\n\n\n", org_contents);
|
||||
|
@ -5,4 +5,6 @@ mod parse;
|
||||
mod sexp;
|
||||
mod util;
|
||||
pub use compare::run_anonymous_compare;
|
||||
pub use compare::run_anonymous_compare_with_settings;
|
||||
pub use compare::run_compare_on_file;
|
||||
pub use compare::run_compare_on_file_with_settings;
|
||||
|
@ -1,8 +1,33 @@
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
pub fn emacs_parse_anonymous_org_document<C>(
|
||||
use crate::context::HeadlineLevelFilter;
|
||||
use crate::settings::GlobalSettings;
|
||||
|
||||
/// Generate elisp to configure org-mode parsing settings
|
||||
///
|
||||
/// Currently only org-list-allow-alphabetical is supported.
|
||||
fn global_settings_elisp(global_settings: &GlobalSettings) -> String {
|
||||
// This string concatenation is wildly inefficient but its only called in tests 🤷.
|
||||
let mut ret = "".to_owned();
|
||||
if global_settings.list_allow_alphabetical {
|
||||
ret += "(setq org-list-allow-alphabetical t)\n"
|
||||
}
|
||||
if global_settings.tab_width != crate::settings::DEFAULT_TAB_WIDTH {
|
||||
ret += format!("(setq-default tab-width {})", global_settings.tab_width).as_str();
|
||||
}
|
||||
if global_settings.odd_levels_only != HeadlineLevelFilter::default() {
|
||||
ret += match global_settings.odd_levels_only {
|
||||
HeadlineLevelFilter::Odd => "(setq org-odd-levels-only t)\n",
|
||||
HeadlineLevelFilter::OddEven => "(setq org-odd-levels-only nil)\n",
|
||||
};
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn emacs_parse_anonymous_org_document<C>(
|
||||
file_contents: C,
|
||||
global_settings: &GlobalSettings,
|
||||
) -> Result<String, Box<dyn std::error::Error>>
|
||||
where
|
||||
C: AsRef<str>,
|
||||
@ -14,10 +39,12 @@ where
|
||||
(require 'org)
|
||||
(defun org-table-align () t)
|
||||
(insert "{escaped_file_contents}")
|
||||
{global_settings}
|
||||
(org-mode)
|
||||
(message "%s" (pp-to-string (org-element-parse-buffer)))
|
||||
)"#,
|
||||
escaped_file_contents = escaped_file_contents
|
||||
escaped_file_contents = escaped_file_contents,
|
||||
global_settings = global_settings_elisp(global_settings)
|
||||
);
|
||||
let mut cmd = Command::new("emacs");
|
||||
let cmd = cmd
|
||||
@ -33,7 +60,10 @@ where
|
||||
Ok(String::from_utf8(org_sexp)?)
|
||||
}
|
||||
|
||||
pub fn emacs_parse_file_org_document<P>(file_path: P) -> Result<String, Box<dyn std::error::Error>>
|
||||
pub(crate) fn emacs_parse_file_org_document<P>(
|
||||
file_path: P,
|
||||
global_settings: &GlobalSettings,
|
||||
) -> Result<String, Box<dyn std::error::Error>>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
@ -46,9 +76,11 @@ where
|
||||
r#"(progn
|
||||
(require 'org)
|
||||
(defun org-table-align () t)
|
||||
{global_settings}
|
||||
(org-mode)
|
||||
(message "%s" (pp-to-string (org-element-parse-buffer)))
|
||||
)"#
|
||||
)"#,
|
||||
global_settings = global_settings_elisp(global_settings)
|
||||
);
|
||||
let mut cmd = Command::new("emacs");
|
||||
let cmd = cmd
|
||||
|
@ -16,7 +16,7 @@ pub struct GlobalSettings<'g, 's> {
|
||||
/// Set to true to allow for plain lists using single letters as the bullet in the same way that numbers are used.
|
||||
///
|
||||
/// Corresponds to the org-list-allow-alphabetical elisp variable.
|
||||
pub org_list_allow_alphabetical: bool,
|
||||
pub list_allow_alphabetical: bool,
|
||||
|
||||
/// How many spaces a tab should be equal to.
|
||||
///
|
||||
@ -29,6 +29,8 @@ pub struct GlobalSettings<'g, 's> {
|
||||
pub odd_levels_only: HeadlineLevelFilter,
|
||||
}
|
||||
|
||||
pub const DEFAULT_TAB_WIDTH: IndentationLevel = 8;
|
||||
|
||||
impl<'g, 's> GlobalSettings<'g, 's> {
|
||||
fn new() -> GlobalSettings<'g, 's> {
|
||||
GlobalSettings {
|
||||
@ -38,9 +40,9 @@ impl<'g, 's> GlobalSettings<'g, 's> {
|
||||
},
|
||||
in_progress_todo_keywords: BTreeSet::new(),
|
||||
complete_todo_keywords: BTreeSet::new(),
|
||||
org_list_allow_alphabetical: false,
|
||||
tab_width: 8,
|
||||
odd_levels_only: HeadlineLevelFilter::OddEven,
|
||||
list_allow_alphabetical: false,
|
||||
tab_width: DEFAULT_TAB_WIDTH,
|
||||
odd_levels_only: HeadlineLevelFilter::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -51,8 +53,14 @@ impl<'g, 's> Default for GlobalSettings<'g, 's> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum HeadlineLevelFilter {
|
||||
Odd,
|
||||
OddEven,
|
||||
}
|
||||
|
||||
impl Default for HeadlineLevelFilter {
|
||||
fn default() -> Self {
|
||||
HeadlineLevelFilter::OddEven
|
||||
}
|
||||
}
|
||||
|
@ -26,5 +26,6 @@ pub use file_access_interface::FileAccessInterface;
|
||||
pub use file_access_interface::LocalFileAccessInterface;
|
||||
pub use global_settings::GlobalSettings;
|
||||
pub use global_settings::HeadlineLevelFilter;
|
||||
pub use global_settings::DEFAULT_TAB_WIDTH;
|
||||
pub(crate) use list::List;
|
||||
pub(crate) use parser_with_context::parser_with_context;
|
||||
|
10
src/lib.rs
10
src/lib.rs
@ -11,6 +11,10 @@ mod iter;
|
||||
pub mod parser;
|
||||
pub mod types;
|
||||
|
||||
pub use context::FileAccessInterface;
|
||||
pub use context::GlobalSettings;
|
||||
pub use context::LocalFileAccessInterface;
|
||||
pub mod settings {
|
||||
pub use crate::context::FileAccessInterface;
|
||||
pub use crate::context::GlobalSettings;
|
||||
pub use crate::context::HeadlineLevelFilter;
|
||||
pub use crate::context::LocalFileAccessInterface;
|
||||
pub use crate::context::DEFAULT_TAB_WIDTH;
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ use std::path::Path;
|
||||
|
||||
use ::organic::parser::parse;
|
||||
use organic::parser::parse_with_settings;
|
||||
use organic::GlobalSettings;
|
||||
use organic::LocalFileAccessInterface;
|
||||
use organic::settings::GlobalSettings;
|
||||
use organic::settings::LocalFileAccessInterface;
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
use crate::init_tracing::init_telemetry;
|
||||
|
@ -11,8 +11,8 @@ use super::OrgSource;
|
||||
use crate::context::HeadlineLevelFilter;
|
||||
use crate::error::CustomError;
|
||||
use crate::error::Res;
|
||||
use crate::settings::GlobalSettings;
|
||||
use crate::types::Keyword;
|
||||
use crate::GlobalSettings;
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
pub(crate) fn scan_for_in_buffer_settings<'s>(
|
||||
|
@ -166,12 +166,8 @@ fn plain_list_item<'b, 'g, 'r, 's>(
|
||||
|(_bullet_type, bull)| Into::<&str>::into(bull) != "*" || indent_level > 0,
|
||||
)(remaining)?;
|
||||
|
||||
let (remaining, _maybe_counter_set) = opt(tuple((
|
||||
space1,
|
||||
tag("[@"),
|
||||
parser_with_context!(counter)(context),
|
||||
tag("]"),
|
||||
)))(remaining)?;
|
||||
let (remaining, _maybe_counter_set) =
|
||||
opt(tuple((space1, tag("[@"), counter_set_value, tag("]"))))(remaining)?;
|
||||
|
||||
let (remaining, maybe_checkbox) = opt(tuple((space1, item_checkbox)))(remaining)?;
|
||||
|
||||
@ -302,7 +298,7 @@ fn counter<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
if context.get_global_settings().org_list_allow_alphabetical {
|
||||
if context.get_global_settings().list_allow_alphabetical {
|
||||
alt((
|
||||
recognize(one_of(
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
@ -314,6 +310,16 @@ fn counter<'b, 'g, 'r, 's>(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn counter_set_value<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
alt((
|
||||
recognize(one_of(
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
)),
|
||||
digit1,
|
||||
))(input)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn plain_list_end<'b, 'g, 'r, 's>(
|
||||
_context: RefContext<'b, 'g, 'r, 's>,
|
||||
|
@ -1,2 +1,5 @@
|
||||
#[cfg(feature = "compare")]
|
||||
#![cfg(feature = "compare")]
|
||||
|
||||
#[feature(exit_status_error)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/tests.rs"));
|
||||
|
@ -1,7 +1,66 @@
|
||||
// TODO: Investigate writing a proc macro to make specifying these combinations easier. For example, currently I am only setting 1 setting per test to keep the repetition reasonable when I should be mixing all the different combinations.
|
||||
|
||||
{expect_fail}
|
||||
#[test]
|
||||
fn {name}() -> Result<(), Box<dyn std::error::Error>> {{
|
||||
fn autogen_default_{name}() -> Result<(), Box<dyn std::error::Error>> {{
|
||||
let org_path = "{path}";
|
||||
let org_contents = std::fs::read_to_string(org_path).expect("Read org file.");
|
||||
organic::compare::run_anonymous_compare(org_contents.as_str())?;
|
||||
Ok(())
|
||||
}}
|
||||
|
||||
{expect_fail}
|
||||
#[test]
|
||||
fn autogen_la_{name}() -> Result<(), Box<dyn std::error::Error>> {{
|
||||
let org_path = "{path}";
|
||||
let org_contents = std::fs::read_to_string(org_path).expect("Read org file.");
|
||||
let global_settings = {{
|
||||
let mut global_settings = organic::settings::GlobalSettings::default();
|
||||
global_settings.list_allow_alphabetical = true;
|
||||
global_settings
|
||||
}};
|
||||
organic::compare::run_anonymous_compare_with_settings(org_contents.as_str(), &global_settings)?;
|
||||
Ok(())
|
||||
}}
|
||||
|
||||
{expect_fail}
|
||||
#[test]
|
||||
fn autogen_t1_{name}() -> Result<(), Box<dyn std::error::Error>> {{
|
||||
let org_path = "{path}";
|
||||
let org_contents = std::fs::read_to_string(org_path).expect("Read org file.");
|
||||
let global_settings = {{
|
||||
let mut global_settings = organic::settings::GlobalSettings::default();
|
||||
global_settings.tab_width = 1;
|
||||
global_settings
|
||||
}};
|
||||
organic::compare::run_anonymous_compare_with_settings(org_contents.as_str(), &global_settings)?;
|
||||
Ok(())
|
||||
}}
|
||||
|
||||
{expect_fail}
|
||||
#[test]
|
||||
fn autogen_t16_{name}() -> Result<(), Box<dyn std::error::Error>> {{
|
||||
let org_path = "{path}";
|
||||
let org_contents = std::fs::read_to_string(org_path).expect("Read org file.");
|
||||
let global_settings = {{
|
||||
let mut global_settings = organic::settings::GlobalSettings::default();
|
||||
global_settings.tab_width = 16;
|
||||
global_settings
|
||||
}};
|
||||
organic::compare::run_anonymous_compare_with_settings(org_contents.as_str(), &global_settings)?;
|
||||
Ok(())
|
||||
}}
|
||||
|
||||
{expect_fail}
|
||||
#[test]
|
||||
fn autogen_odd_{name}() -> Result<(), Box<dyn std::error::Error>> {{
|
||||
let org_path = "{path}";
|
||||
let org_contents = std::fs::read_to_string(org_path).expect("Read org file.");
|
||||
let global_settings = {{
|
||||
let mut global_settings = organic::settings::GlobalSettings::default();
|
||||
global_settings.odd_levels_only = organic::settings::HeadlineLevelFilter::Odd;
|
||||
global_settings
|
||||
}};
|
||||
organic::compare::run_anonymous_compare_with_settings(org_contents.as_str(), &global_settings)?;
|
||||
Ok(())
|
||||
}}
|
||||
|
Loading…
Reference in New Issue
Block a user