diff --git a/Cargo.lock b/Cargo.lock index 7a55a053..364a78a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1318,8 +1318,8 @@ dependencies = [ [[package]] name = "tree-sitter-bash" -version = "0.20.4" -source = "git+https://github.com/tree-sitter/tree-sitter-bash#1479a4030f1a399c253aee02097576d4af46f23a" +version = "0.19.0" +source = "git+https://github.com/tree-sitter/tree-sitter-bash#1b0321ee85701d5036c334a6f04761cdc672e64c" dependencies = [ "cc", "tree-sitter", diff --git a/topiary-cli/src/configuration/serde.rs b/topiary-cli/src/configuration/serde.rs index 9886a48d..054e6779 100644 --- a/topiary-cli/src/configuration/serde.rs +++ b/topiary-cli/src/configuration/serde.rs @@ -181,6 +181,12 @@ impl Serialisation { } } +impl Default for Serialisation { + fn default() -> Self { + Self::new() + } +} + /// Convert deserialised TOML values into `Serialisation` values // TODO Is this necessary, any more? impl TryFrom for Serialisation { diff --git a/topiary-cli/src/io.rs b/topiary-cli/src/io.rs index 22b50060..a207a17b 100644 --- a/topiary-cli/src/io.rs +++ b/topiary-cli/src/io.rs @@ -129,8 +129,8 @@ impl<'cfg> InputFile<'cfg> { Ok(LanguageDefinition { language: Language { name: self.language.name.clone(), - query: query, - grammar: grammar, + query, + grammar, indent: self.language().indent.clone(), }, }) diff --git a/topiary-cli/tests/sample-tester.rs b/topiary-cli/tests/sample-tester.rs new file mode 100644 index 00000000..2ac51470 --- /dev/null +++ b/topiary-cli/tests/sample-tester.rs @@ -0,0 +1,76 @@ +use assert_cmd::Command; +use std::fs; +use std::path::Path; +use topiary::test_utils::pretty_assert_eq; + +use tempfile::TempDir; + +#[test] +fn input_output_tester() { + let input_dir = fs::read_dir("tests/samples/input").unwrap(); + let expected_dir = Path::new("tests/samples/expected"); + + for file in input_dir { + let file = file.unwrap(); + + // Load the known good formated files + let expected_path = expected_dir.join(file.file_name()); + let expected = fs::read_to_string(expected_path).unwrap(); + + let tmp_dir = TempDir::new().unwrap(); + + // Copy the file to a temp dir + let mut input_file = tmp_dir.path().to_path_buf(); + input_file.push(file.path().file_name().unwrap()); + fs::copy(file.path(), &input_file).unwrap(); + + // Run topiary on the input file in the temp dir + let mut topiary = Command::cargo_bin("topiary").unwrap(); + topiary + // .env("TOPIARY_LANGUAGE_DIR", "../queries/") + .arg("fmt") + .arg(&input_file) + .assert() + .success(); + + // Read the file after formatting + let formatted = fs::read_to_string(input_file).unwrap(); + + // Assert the formatted file is as expected + pretty_assert_eq(&expected, &formatted); + } +} + +// Test that our query files are properly formatted +#[test] +fn formatted_query_tester() { + let language_dir = fs::read_dir("../queries").unwrap(); + + for file in language_dir { + let file = file.unwrap(); + + // Load the query file (we assume is formatted correctly) + let expected = fs::read_to_string(file.path()).unwrap(); + + let tmp_dir = TempDir::new().unwrap(); + + // Copy the file to a temp dir + let mut input_file = tmp_dir.path().to_path_buf(); + input_file.push(file.path().file_name().unwrap()); + fs::copy(file.path(), &input_file).unwrap(); + + // Run topiary on the input file in the temp dir + let mut topiary = Command::cargo_bin("topiary").unwrap(); + topiary + // .env("TOPIARY_LANGUAGE_DIR", "../queries/") + .arg("fmt") + .arg(&input_file) + .assert() + .success(); + + // Read the file after formatting + let formatted = fs::read_to_string(input_file).unwrap(); + + pretty_assert_eq(&expected, &formatted); + } +} diff --git a/topiary/tests/samples/expected/bash.sh b/topiary-cli/tests/samples/expected/bash.sh similarity index 100% rename from topiary/tests/samples/expected/bash.sh rename to topiary-cli/tests/samples/expected/bash.sh diff --git a/topiary/tests/samples/expected/json.json b/topiary-cli/tests/samples/expected/json.json similarity index 100% rename from topiary/tests/samples/expected/json.json rename to topiary-cli/tests/samples/expected/json.json diff --git a/topiary/tests/samples/expected/nickel.ncl b/topiary-cli/tests/samples/expected/nickel.ncl similarity index 100% rename from topiary/tests/samples/expected/nickel.ncl rename to topiary-cli/tests/samples/expected/nickel.ncl diff --git a/topiary/tests/samples/expected/ocaml-interface.mli b/topiary-cli/tests/samples/expected/ocaml-interface.mli similarity index 100% rename from topiary/tests/samples/expected/ocaml-interface.mli rename to topiary-cli/tests/samples/expected/ocaml-interface.mli diff --git a/topiary/tests/samples/expected/ocaml.ml b/topiary-cli/tests/samples/expected/ocaml.ml similarity index 100% rename from topiary/tests/samples/expected/ocaml.ml rename to topiary-cli/tests/samples/expected/ocaml.ml diff --git a/topiary/tests/samples/expected/ocamllex.mll b/topiary-cli/tests/samples/expected/ocamllex.mll similarity index 100% rename from topiary/tests/samples/expected/ocamllex.mll rename to topiary-cli/tests/samples/expected/ocamllex.mll diff --git a/topiary/tests/samples/expected/rust.rs b/topiary-cli/tests/samples/expected/rust.rs similarity index 100% rename from topiary/tests/samples/expected/rust.rs rename to topiary-cli/tests/samples/expected/rust.rs diff --git a/topiary/tests/samples/expected/toml.toml b/topiary-cli/tests/samples/expected/toml.toml similarity index 100% rename from topiary/tests/samples/expected/toml.toml rename to topiary-cli/tests/samples/expected/toml.toml diff --git a/topiary/tests/samples/expected/tree-sitter-query.scm b/topiary-cli/tests/samples/expected/tree-sitter-query.scm similarity index 100% rename from topiary/tests/samples/expected/tree-sitter-query.scm rename to topiary-cli/tests/samples/expected/tree-sitter-query.scm diff --git a/topiary/tests/samples/input/bash.sh b/topiary-cli/tests/samples/input/bash.sh similarity index 100% rename from topiary/tests/samples/input/bash.sh rename to topiary-cli/tests/samples/input/bash.sh diff --git a/topiary/tests/samples/input/json.json b/topiary-cli/tests/samples/input/json.json similarity index 100% rename from topiary/tests/samples/input/json.json rename to topiary-cli/tests/samples/input/json.json diff --git a/topiary/tests/samples/input/nickel.ncl b/topiary-cli/tests/samples/input/nickel.ncl similarity index 100% rename from topiary/tests/samples/input/nickel.ncl rename to topiary-cli/tests/samples/input/nickel.ncl diff --git a/topiary/tests/samples/input/ocaml-interface.mli b/topiary-cli/tests/samples/input/ocaml-interface.mli similarity index 100% rename from topiary/tests/samples/input/ocaml-interface.mli rename to topiary-cli/tests/samples/input/ocaml-interface.mli diff --git a/topiary/tests/samples/input/ocaml.ml b/topiary-cli/tests/samples/input/ocaml.ml similarity index 100% rename from topiary/tests/samples/input/ocaml.ml rename to topiary-cli/tests/samples/input/ocaml.ml diff --git a/topiary/tests/samples/input/ocamllex.mll b/topiary-cli/tests/samples/input/ocamllex.mll similarity index 100% rename from topiary/tests/samples/input/ocamllex.mll rename to topiary-cli/tests/samples/input/ocamllex.mll diff --git a/topiary/tests/samples/input/rust.rs b/topiary-cli/tests/samples/input/rust.rs similarity index 100% rename from topiary/tests/samples/input/rust.rs rename to topiary-cli/tests/samples/input/rust.rs diff --git a/topiary/tests/samples/input/toml.toml b/topiary-cli/tests/samples/input/toml.toml similarity index 100% rename from topiary/tests/samples/input/toml.toml rename to topiary-cli/tests/samples/input/toml.toml diff --git a/topiary/tests/samples/input/tree-sitter-query.scm b/topiary-cli/tests/samples/input/tree-sitter-query.scm similarity index 100% rename from topiary/tests/samples/input/tree-sitter-query.scm rename to topiary-cli/tests/samples/input/tree-sitter-query.scm diff --git a/topiary/benches/benchmark.rs b/topiary/benches/benchmark.rs index f7777dfd..ac2eff73 100644 --- a/topiary/benches/benchmark.rs +++ b/topiary/benches/benchmark.rs @@ -7,7 +7,7 @@ use topiary::{formatter, Language, Operation, TopiaryQuery}; // FIXME Configuration is no longer part of the library async fn format() { - let input = fs::read_to_string("tests/samples/input/ocaml.ml").unwrap(); + let input = fs::read_to_string("../topiary-cli/tests/samples/input/ocaml.ml").unwrap(); let query_content = fs::read_to_string("../queries/ocaml.scm").unwrap(); let ocaml = tree_sitter_ocaml::language_ocaml(); diff --git a/topiary/src/lib.rs b/topiary/src/lib.rs index f863b413..8489d010 100644 --- a/topiary/src/lib.rs +++ b/topiary/src/lib.rs @@ -159,20 +159,25 @@ pub enum Operation { /// # tokio_test::block_on(async { /// use std::fs::File; /// use std::io::{BufReader, Read}; -/// use topiary::{formatter, FormatterError, TopiaryQuery, Operation}; +/// use topiary::{formatter, Language, FormatterError, TopiaryQuery, Operation}; /// /// let input = "[1,2]".to_string(); /// let mut input = input.as_bytes(); /// let mut output = Vec::new(); +/// let json = tree_sitter_json::language(); +/// /// let mut query_file = BufReader::new(File::open("../queries/json.scm").expect("query file")); /// let mut query_content = String::new(); /// query_file.read_to_string(&mut query_content).expect("read query file"); /// -/// let grammar = tree_sitter_json::language(); -/// let query = TopiaryQuery::new(&grammar, &query_content).unwrap(); +/// let language: Language = Language { +/// name: "json".to_owned(), +/// query: TopiaryQuery::new(&json.into(), &query_content).unwrap(), +/// grammar: json.into(), +/// indent: None, +/// }; /// -/// // FIXME The signature of `formatter` has changed -/// match formatter(&mut input, &mut output, &query, &language, &grammar, Operation::Format{ skip_idempotence: false, tolerate_parsing_errors: false }) { +/// match formatter(&mut input, &mut output, &language, Operation::Format{ skip_idempotence: false, tolerate_parsing_errors: false }) { /// Ok(()) => { /// let formatted = String::from_utf8(output).expect("valid utf-8"); /// } @@ -359,7 +364,7 @@ mod tests { let expected = "{ \"one\": {\"bar\" \"baz\"}, \"two\": \"bar\" }\n"; let mut output = Vec::new(); - let query_content = fs::read_to_string("../languages/json.scm").unwrap(); + let query_content = fs::read_to_string("../topiary-queries/queries/json.scm").unwrap(); let grammar = tree_sitter_json::language().into(); let language = Language { name: "json".to_owned(), diff --git a/topiary/tests/sample-tester.rs b/topiary/tests/sample-tester.rs deleted file mode 100644 index e4a3dd30..00000000 --- a/topiary/tests/sample-tester.rs +++ /dev/null @@ -1,141 +0,0 @@ -use std::fs; -use std::io::BufReader; -use std::path::Path; - -use log::info; -use test_log::test; - -use topiary::{ - apply_query, formatter, test_utils::pretty_assert_eq, Configuration, FormatterError, Language, - Operation, TopiaryQuery, -}; - -// FIXME Configuration is no longer part of the library - -#[test(tokio::test)] -async fn input_output_tester() { - let input_dir = fs::read_dir("tests/samples/input").unwrap(); - let expected_dir = Path::new("tests/samples/expected"); - let config = Configuration::parse_default_configuration().unwrap(); - let extensions = config.known_extensions(); - - for file in input_dir { - let file = file.unwrap(); - if let Some(ext) = file.path().extension().map(|ext| ext.to_string_lossy()) { - if !extensions.contains(ext.as_ref()) { - continue; - } - - let language = Language::detect(file.path(), &config).unwrap(); - - let expected_path = expected_dir.join(file.file_name()); - let expected = fs::read_to_string(expected_path).unwrap(); - - let mut input = BufReader::new(fs::File::open(file.path()).unwrap()); - let mut output = Vec::new(); - let query_content = fs::read_to_string(language.query_file().unwrap()).unwrap(); - - let grammar = language.grammar().await.unwrap(); - - let query = TopiaryQuery::new(&grammar, &query_content).unwrap(); - - info!( - "Formatting file {} as {}.", - file.path().display(), - language.name, - ); - - info!("Formatting {}", file.path().display()); - - formatter( - &mut input, - &mut output, - &query, - language, - &grammar, - Operation::Format { - skip_idempotence: false, - tolerate_parsing_errors: true, - }, - ) - .unwrap(); - - let formatted = String::from_utf8(output).unwrap(); - log::debug!("{}", formatted); - - pretty_assert_eq(&expected, &formatted); - } - } -} - -// Test that our query files are properly formatted -#[test(tokio::test)] -async fn formatted_query_tester() { - let config = Configuration::parse_default_configuration().unwrap(); - let language_dir = fs::read_dir("../queries").unwrap(); - - for file in language_dir { - let file = file.unwrap(); - let language = Language::detect(file.path(), &config).unwrap(); - - let expected = fs::read_to_string(file.path()).unwrap(); - - let mut input = BufReader::new(fs::File::open(file.path()).unwrap()); - let mut output = Vec::new(); - let query_content = fs::read_to_string(language.query_file().unwrap()).unwrap(); - - let grammar = language.grammar().await.unwrap(); - - let query = TopiaryQuery::new(&grammar, &query_content).unwrap(); - - formatter( - &mut input, - &mut output, - &query, - language, - &grammar, - Operation::Format { - skip_idempotence: false, - tolerate_parsing_errors: false, - }, - ) - .unwrap(); - - let formatted = String::from_utf8(output).unwrap(); - log::debug!("{}", formatted); - - pretty_assert_eq(&expected, &formatted); - } -} - -// Test that all queries are used on sample files -#[test(tokio::test)] -async fn exhaustive_query_tester() { - let config = Configuration::parse_default_configuration().unwrap(); - let input_dir = fs::read_dir("tests/samples/input").unwrap(); - - for file in input_dir { - let file = file.unwrap(); - // We skip "ocaml-interface.mli", as its query file is already tested by "ocaml.ml" - if file.file_name().to_string_lossy() == "ocaml-interface.mli" { - continue; - } - let language = Language::detect(file.path(), &config).unwrap(); - let query_file = language.query_file().unwrap(); - - let input_content = fs::read_to_string(&file.path()).unwrap(); - let query_content = fs::read_to_string(&query_file).unwrap(); - - let grammar = language.grammar().await.unwrap(); - - let query = TopiaryQuery::new(&grammar, &query_content).unwrap(); - - apply_query(&input_content, &query, &grammar, false, true).unwrap_or_else(|e| { - if let FormatterError::PatternDoesNotMatch(_) = e { - panic!("Found untested query in file {query_file:?}:\n{e}"); - } else { - panic!("{e}"); - } - }); - } -}