From f263a4fbe335404c6f79048187b57f6184587602 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 1 Feb 2019 21:20:27 -0800 Subject: [PATCH] Separate walk_with_properties tests from parser tests --- cli/src/main.rs | 2 +- cli/src/properties.rs | 7 +- cli/src/tests/mod.rs | 3 +- .../{parser_api_test.rs => parser_test.rs} | 199 +----------------- cli/src/tests/properties_test.rs | 134 ++++++++++++ 5 files changed, 145 insertions(+), 200 deletions(-) rename cli/src/tests/{parser_api_test.rs => parser_test.rs} (58%) create mode 100644 cli/src/tests/properties_test.rs diff --git a/cli/src/main.rs b/cli/src/main.rs index 4d4dc1c6..299ab896 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -95,7 +95,7 @@ fn run() -> error::Result<()> { state_ids_to_log, )?; } - properties::generate_property_sheets(¤t_dir)?; + properties::generate_property_sheets_in_directory(¤t_dir)?; } else if let Some(matches) = matches.subcommand_matches("test") { let debug = matches.is_present("debug"); let debug_graph = matches.is_present("debug-graph"); diff --git a/cli/src/properties.rs b/cli/src/properties.rs index f5861159..fccfd7ed 100644 --- a/cli/src/properties.rs +++ b/cli/src/properties.rs @@ -421,7 +421,7 @@ impl fmt::Debug for Selector { } } -pub fn generate_property_sheets(repo_path: &Path) -> Result<()> { +pub fn generate_property_sheets_in_directory(repo_path: &Path) -> Result<()> { let src_dir_path = repo_path.join("src"); let properties_dir_path = repo_path.join("properties"); @@ -443,6 +443,11 @@ pub fn generate_property_sheets(repo_path: &Path) -> Result<()> { Ok(()) } +pub fn generate_property_sheet_string(path: impl AsRef, css: &str) -> Result { + let sheet = generate_property_sheet(path, css)?; + Ok(serde_json::to_string(&sheet)?) +} + fn generate_property_sheet(path: impl AsRef, css: &str) -> Result { let rules = parse_property_sheet(path.as_ref(), &css)?; Ok(Builder::new(rules).build()) diff --git a/cli/src/tests/mod.rs b/cli/src/tests/mod.rs index 3641cc3e..b8f6ad1f 100644 --- a/cli/src/tests/mod.rs +++ b/cli/src/tests/mod.rs @@ -1,4 +1,5 @@ mod corpus_test; mod helpers; -mod parser_api_test; +mod parser_test; +mod properties_test; mod tree_test; diff --git a/cli/src/tests/parser_api_test.rs b/cli/src/tests/parser_test.rs similarity index 58% rename from cli/src/tests/parser_api_test.rs rename to cli/src/tests/parser_test.rs index e46d9b55..a061d8c6 100644 --- a/cli/src/tests/parser_api_test.rs +++ b/cli/src/tests/parser_test.rs @@ -1,7 +1,6 @@ use super::helpers::fixtures::get_language; -use serde_derive::Deserialize; use std::thread; -use tree_sitter::{InputEdit, Language, LogType, Parser, Point, PropertySheet}; +use tree_sitter::{InputEdit, Language, LogType, Parser, Point}; #[test] fn test_basic_parsing() { @@ -93,200 +92,6 @@ fn test_tree_cursor() { assert_eq!(cursor.node().is_named(), true); } -#[test] -fn test_tree_property_matching() { - let mut parser = Parser::new(); - parser.set_language(rust()).unwrap(); - let source_code = "fn f1() { f2(); }"; - let tree = parser.parse_str(source_code, None).unwrap(); - - #[derive(Debug, Deserialize, PartialEq, Eq)] - struct Properties { - reference: Option, - define: Option, - } - - let empty_properties = Properties { - reference: None, - define: None, - }; - - let property_sheet = PropertySheet::::new( - rust(), - r##" - { - "states": [ - { - "transitions": [ - {"type": "call_expression", "named": true, "state_id": 1}, - {"type": "function_item", "named": true, "state_id": 2} - ], - "default_next_state_id": 0, - "property_set_id": 0 - }, - { - "transitions": [ - {"type": "identifier", "named": true, "state_id": 3} - ], - "default_next_state_id": 0, - "property_set_id": 0 - }, - { - "transitions": [ - {"type": "identifier", "named": true, "state_id": 4} - ], - "default_next_state_id": 0, - "property_set_id": 0 - }, - { - "transitions": [], - "default_next_state_id": 0, - "property_set_id": 1 - }, - { - "transitions": [], - "default_next_state_id": 0, - "property_set_id": 2 - } - ], - "property_sets": [ - {}, - {"reference": "function"}, - {"define": "function"} - ] - } - "##, - ) - .unwrap(); - - let mut cursor = tree.walk_with_properties(&property_sheet, source_code); - assert_eq!(cursor.node().kind(), "source_file"); - assert_eq!(*cursor.node_properties(), empty_properties); - - assert!(cursor.goto_first_child()); - assert_eq!(cursor.node().kind(), "function_item"); - assert_eq!(*cursor.node_properties(), empty_properties); - - assert!(cursor.goto_first_child()); - assert_eq!(cursor.node().kind(), "fn"); - assert_eq!(*cursor.node_properties(), empty_properties); - assert!(!cursor.goto_first_child()); - - assert!(cursor.goto_next_sibling()); - assert_eq!(cursor.node().kind(), "identifier"); - assert_eq!(cursor.node_properties().define, Some("function".to_owned())); - assert!(!cursor.goto_first_child()); - - assert!(cursor.goto_next_sibling()); - assert_eq!(cursor.node().kind(), "parameters"); - assert_eq!(*cursor.node_properties(), empty_properties); - - assert!(cursor.goto_first_child()); - assert_eq!(cursor.node().kind(), "("); - assert!(cursor.goto_next_sibling()); - assert_eq!(cursor.node().kind(), ")"); - assert_eq!(*cursor.node_properties(), empty_properties); - - assert!(cursor.goto_parent()); - assert!(cursor.goto_next_sibling()); - assert_eq!(cursor.node().kind(), "block"); - assert_eq!(*cursor.node_properties(), empty_properties); - - assert!(cursor.goto_first_child()); - assert!(cursor.goto_next_sibling()); - assert_eq!(cursor.node().kind(), "call_expression"); - assert_eq!(*cursor.node_properties(), empty_properties); - - assert!(cursor.goto_first_child()); - assert_eq!(cursor.node().kind(), "identifier"); - assert_eq!( - cursor.node_properties().reference, - Some("function".to_owned()) - ); -} - -#[test] -fn test_tree_property_matching_with_regexes() { - let mut parser = Parser::new(); - parser.set_language(rust()).unwrap(); - let source_code = "fn f1() { None(a()) }"; - let tree = parser.parse_str(source_code, None).unwrap(); - - #[derive(Debug, Deserialize, PartialEq, Eq)] - struct Properties { - scope: Option, - } - - let empty_properties = Properties { scope: None }; - - let property_sheet = PropertySheet::::new( - rust(), - r##" - { - "states": [ - { - "id": 0, - "transitions": [ - {"type": "call_expression", "named": true, "state_id": 1} - ], - "default_next_state_id": 0, - "property_set_id": 0 - }, - { - "id": 1, - "transitions": [ - {"type": "identifier", "named": true, "text": "^[A-Z]", "state_id": 2}, - {"type": "identifier", "named": true, "state_id": 3} - ], - "default_next_state_id": 0, - "property_set_id": 0 - }, - { - "transitions": [], - "default_next_state_id": 0, - "property_set_id": 1 - }, - { - "transitions": [], - "default_next_state_id": 0, - "property_set_id": 2 - } - ], - "property_sets": [ - {}, - {"scope": "constructor"}, - {"scope": "function"} - ] - } - "##, - ) - .unwrap(); - - let mut cursor = tree.walk_with_properties(&property_sheet, source_code); - assert_eq!(cursor.node().kind(), "source_file"); - assert_eq!(*cursor.node_properties(), empty_properties); - - cursor.goto_first_child(); - assert!(cursor.goto_first_child()); - assert!(cursor.goto_next_sibling()); - assert!(cursor.goto_next_sibling()); - assert!(cursor.goto_next_sibling()); - assert_eq!(cursor.node().kind(), "block"); - assert_eq!(*cursor.node_properties(), empty_properties); - - assert!(cursor.goto_first_child()); - assert!(cursor.goto_next_sibling()); - assert_eq!(cursor.node().kind(), "call_expression"); - assert_eq!(*cursor.node_properties(), empty_properties); - - assert!(cursor.goto_first_child()); - assert_eq!(cursor.node().kind(), "identifier"); - assert_eq!( - cursor.node_properties().scope, - Some("constructor".to_owned()) - ); -} - #[test] fn test_custom_utf8_input() { let mut parser = Parser::new(); @@ -454,7 +259,7 @@ fn test_editing() { fn test_parallel_parsing() { // Parse this source file so that each thread has a non-trivial amount of // work to do. - let this_file_source = include_str!("parser_api_test.rs"); + let this_file_source = include_str!("parser_test.rs"); let mut parser = Parser::new(); parser.set_language(rust()).unwrap(); diff --git a/cli/src/tests/properties_test.rs b/cli/src/tests/properties_test.rs new file mode 100644 index 00000000..213eb9d0 --- /dev/null +++ b/cli/src/tests/properties_test.rs @@ -0,0 +1,134 @@ +use super::helpers::fixtures::get_language; +use crate::properties; +use serde_derive::Deserialize; +use tree_sitter::{Parser, PropertySheet}; + +#[derive(Debug, Default, Deserialize, PartialEq, Eq)] +struct Properties { + a: Option, + b: Option, +} + +#[test] +fn test_walk_with_properties_with_nth_child() { + let language = get_language("javascript"); + let property_sheet = PropertySheet::::new( + language, + &properties::generate_property_sheet_string( + "/some/path.css", + " + binary_expression > identifier:nth-child(2) { + a: x; + } + + binary_expression > identifier { + a: y; + } + + identifier { + a: z; + } + ", + ) + .unwrap(), + ) + .unwrap(); + + let source_code = "a = b || c;"; + + let mut parser = Parser::new(); + parser.set_language(language).unwrap(); + let tree = parser.parse_str(source_code, None).unwrap(); + + let mut cursor = tree.walk_with_properties(&property_sheet, source_code); + assert_eq!(cursor.node().kind(), "program"); + assert!(cursor.goto_first_child()); + assert_eq!(cursor.node().kind(), "expression_statement"); + assert!(cursor.goto_first_child()); + assert_eq!(cursor.node().kind(), "assignment_expression"); + + assert!(cursor.goto_first_child()); + assert_eq!(cursor.node().kind(), "identifier"); + assert_eq!(*cursor.node_properties(), Properties { a: Some("z".to_string()), b: None }); + + assert!(cursor.goto_next_sibling()); + assert_eq!(cursor.node().kind(), "="); + assert!(cursor.goto_next_sibling()); + assert_eq!(cursor.node().kind(), "binary_expression"); + + assert!(cursor.goto_first_child()); + assert_eq!(cursor.node().kind(), "identifier"); + assert_eq!(*cursor.node_properties(), Properties { a: Some("y".to_string()), b: None }); + + assert!(cursor.goto_next_sibling()); + assert_eq!(cursor.node().kind(), "||"); + assert!(cursor.goto_next_sibling()); + assert_eq!(cursor.node().kind(), "identifier"); + assert_eq!(*cursor.node_properties(), Properties { a: Some("x".to_string()), b: None }); +} + +#[test] +fn test_walk_with_properties_with_regexes() { + let language = get_language("javascript"); + let property_sheet = PropertySheet::::new( + language, + &properties::generate_property_sheet_string( + "/some/path.css", + " + identifier { + &[text='^[A-Z]'] { + a: y; + } + + &[text='^[A-Z_]+$'] { + a: z; + } + + a: x; + } + ", + ) + .unwrap(), + ) + .unwrap(); + + let source_code = "const ABC = Def(ghi);"; + + let mut parser = Parser::new(); + parser.set_language(language).unwrap(); + let tree = parser.parse_str(source_code, None).unwrap(); + + let mut cursor = tree.walk_with_properties(&property_sheet, source_code); + assert_eq!(cursor.node().kind(), "program"); + assert!(cursor.goto_first_child()); + assert_eq!(cursor.node().kind(), "lexical_declaration"); + assert!(cursor.goto_first_child()); + assert_eq!(cursor.node().kind(), "const"); + assert!(cursor.goto_next_sibling()); + assert_eq!(cursor.node().kind(), "variable_declarator"); + + // The later selector with a text regex overrides the earlier one. + assert!(cursor.goto_first_child()); + assert_eq!(cursor.node().kind(), "identifier"); + assert_eq!(*cursor.node_properties(), Properties { a: Some("z".to_string()), b: None }); + + assert!(cursor.goto_next_sibling()); + assert_eq!(cursor.node().kind(), "="); + assert!(cursor.goto_next_sibling()); + assert_eq!(cursor.node().kind(), "call_expression"); + + // The selectors with text regexes override the selector without one. + assert!(cursor.goto_first_child()); + assert_eq!(cursor.node().kind(), "identifier"); + assert_eq!(*cursor.node_properties(), Properties { a: Some("y".to_string()), b: None }); + + assert!(cursor.goto_next_sibling()); + assert_eq!(cursor.node().kind(), "arguments"); + assert!(cursor.goto_first_child()); + assert_eq!(cursor.node().kind(), "("); + + // This node doesn't match either of the regexes. + assert!(cursor.goto_next_sibling()); + assert_eq!(cursor.node().kind(), "identifier"); + assert_eq!(*cursor.node_properties(), Properties { a: Some("x".to_string()), b: None }); +}