From befb3759a7da2dde9f0d0295e330605f339a8e73 Mon Sep 17 00:00:00 2001 From: Ameya Ketkar <94497232+ketkarameya@users.noreply.github.com> Date: Mon, 21 Aug 2023 15:31:26 -0700 Subject: [PATCH] Allow the user to specify multiple paths to codebase --- .pre-commit-config.yaml | 6 +- src/lib.rs | 7 +- src/models/default_configs.rs | 4 +- src/models/language.rs | 6 +- src/models/piranha_arguments.rs | 18 ++--- src/models/rule_store.rs | 77 ++++++++++++------- .../unit_tests/piranha_arguments_test.rs | 2 +- src/models/unit_tests/rule_test.rs | 10 +-- .../unit_tests/source_code_unit_test.rs | 16 ++-- src/tests/mod.rs | 9 +-- src/tests/test_piranha_java.rs | 43 ++++++++--- src/tests/test_piranha_swift.rs | 2 +- .../folder_1/Sample.java | 3 + .../folder_2/Sample.java | 3 + .../folder_3/Sample.java | 3 + 15 files changed, 133 insertions(+), 76 deletions(-) create mode 100644 test-resources/java/structural_find_replace_multiple_code_bases/folder_1/Sample.java create mode 100644 test-resources/java/structural_find_replace_multiple_code_bases/folder_2/Sample.java create mode 100644 test-resources/java/structural_find_replace_multiple_code_bases/folder_3/Sample.java diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c139dd06b6..d557c71a48 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.1.0 + rev: v4.4.0 hooks: - id: check-byte-order-marker - id: check-case-conflict @@ -51,13 +51,13 @@ repos: - --comment-style - "#" - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: "v2.0.1" + rev: "v2.0.2" hooks: - id: autopep8 files: demo/ exclude: only_lists.py - repo: https://github.com/pre-commit/mirrors-prettier - rev: "" # Use the sha or tag you want to point at + rev: "v3.0.2" # Use the sha or tag you want to point at hooks: - id: prettier files: ^experimental/piranha_playground/ diff --git a/src/lib.rs b/src/lib.rs index b8d39edb6b..8c8c5d94d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -118,11 +118,12 @@ impl Piranha { let mut parser = piranha_args.language().parser(); - let mut path_to_codebase = self.piranha_arguments.path_to_codebase().to_string(); + let mut paths_to_codebase = self.piranha_arguments.paths_to_codebase().clone(); let temp_dir = if !self.piranha_arguments.code_snippet().is_empty() { let td = self.write_code_snippet_to_temp(); - path_to_codebase = td.path().to_str().unwrap_or_default().to_string(); + // let td_path = td.path().to_str().unwrap().to_string(); + paths_to_codebase = vec![td.path().to_str().unwrap_or_default().to_string()]; Some(td) } else { None @@ -137,7 +138,7 @@ impl Piranha { // Iterate over each file containing the usage of the feature flag API for (path, content) in self.rule_store.get_relevant_files( - &path_to_codebase, + &paths_to_codebase, piranha_args.include(), piranha_args.exclude(), ) { diff --git a/src/models/default_configs.rs b/src/models/default_configs.rs index c4d14e3768..c4532d3d74 100644 --- a/src/models/default_configs.rs +++ b/src/models/default_configs.rs @@ -72,8 +72,8 @@ pub fn default_dry_run() -> bool { false } -pub fn default_path_to_codebase() -> String { - String::new() +pub fn default_paths_to_codebase() -> Vec { + Vec::new() } pub fn default_code_snippet() -> String { diff --git a/src/models/language.rs b/src/models/language.rs index 873769d874..e10c8c6216 100644 --- a/src/models/language.rs +++ b/src/models/language.rs @@ -11,7 +11,7 @@ limitations under the License. */ -use std::str::FromStr; +use std::{path::PathBuf, str::FromStr}; use getset::Getters; use serde_derive::Deserialize; @@ -91,8 +91,8 @@ impl PiranhaLanguage { parser } - pub(crate) fn can_parse(&self, de: &jwalk::DirEntry<((), ())>) -> bool { - de.path() + pub(crate) fn can_parse(&self, path: &PathBuf) -> bool { + path .extension() .and_then(|e| e.to_str().filter(|x| x.eq(&self.extension()))) .is_some() diff --git a/src/models/piranha_arguments.rs b/src/models/piranha_arguments.rs index cc19c21279..e7f4417f3e 100644 --- a/src/models/piranha_arguments.rs +++ b/src/models/piranha_arguments.rs @@ -16,8 +16,8 @@ use super::{ default_allow_dirty_ast, default_cleanup_comments, default_cleanup_comments_buffer, default_code_snippet, default_delete_consecutive_new_lines, default_delete_file_if_empty, default_dry_run, default_exclude, default_global_tag_prefix, default_graph_validation, - default_include, default_number_of_ancestors_in_parent_scope, default_path_to_codebase, - default_path_to_configurations, default_path_to_output_summaries, default_piranha_language, + default_include, default_number_of_ancestors_in_parent_scope, default_path_to_configurations, + default_path_to_output_summaries, default_paths_to_codebase, default_piranha_language, default_rule_graph, default_substitutions, GO, JAVA, KOTLIN, PYTHON, SWIFT, TSX, TYPESCRIPT, }, language::PiranhaLanguage, @@ -50,9 +50,9 @@ use std::collections::HashMap; pub struct PiranhaArguments { /// Path to source code folder or file #[get = "pub"] - #[builder(default = "default_path_to_codebase()")] + #[builder(default = "default_paths_to_codebase()")] #[clap(short = 'c', long, required = true)] - path_to_codebase: String, + paths_to_codebase: Vec, /// Paths to include (as glob patterns) #[get = "pub"] @@ -191,7 +191,7 @@ impl PiranhaArguments { /// Returns PiranhaArgument. #[new] fn py_new( - language: String, path_to_codebase: Option, include: Option>, + language: String, paths_to_codebase: Vec, include: Option>, exclude: Option>, substitutions: Option<&PyDict>, path_to_configurations: Option, rule_graph: Option, code_snippet: Option, dry_run: Option, cleanup_comments: Option, @@ -208,7 +208,7 @@ impl PiranhaArguments { let rg = rule_graph.unwrap_or_else(|| RuleGraphBuilder::default().build()); PiranhaArgumentsBuilder::default() - .path_to_codebase(path_to_codebase.unwrap_or_else(default_path_to_codebase)) + .paths_to_codebase(paths_to_codebase) .include( include .unwrap_or_default() @@ -258,7 +258,7 @@ impl PiranhaArguments { pub fn from_cli() -> Self { let p = PiranhaArguments::parse(); PiranhaArgumentsBuilder::default() - .path_to_codebase(p.path_to_codebase().to_string()) + .paths_to_codebase(p.paths_to_codebase().clone()) .substitutions(p.substitutions.clone()) .language(p.language().clone()) .path_to_configurations(p.path_to_configurations().to_string()) @@ -344,14 +344,14 @@ fn get_rule_graph(_arg: &PiranhaArguments) -> RuleGraph { impl Validator for PiranhaArguments { fn validate(&self) -> Result<(), String> { let _arg: PiranhaArguments = self.clone(); - if _arg.code_snippet().is_empty() && _arg.path_to_codebase().is_empty() { + if _arg.code_snippet().is_empty() && _arg.paths_to_codebase().is_empty() { return Err( "Invalid Piranha Argument. Missing `path_to_codebase` or `code_snippet`. Please specify the `path_to_codebase` or `code_snippet` when creating PiranhaArgument !!!" .to_string(), ); } - if !_arg.code_snippet().is_empty() && !_arg.path_to_codebase().is_empty() { + if !_arg.code_snippet().is_empty() && !_arg.paths_to_codebase().is_empty() { return Err( "Invalid Piranha arguments. Please either specify the `path_to_codebase` or the `code_snippet`. Not Both." .to_string(), diff --git a/src/models/rule_store.rs b/src/models/rule_store.rs index 6b1e21b3ba..046f012d18 100644 --- a/src/models/rule_store.rs +++ b/src/models/rule_store.rs @@ -143,19 +143,58 @@ impl RuleStore { /// Note that `WalkDir` traverses the directory with parallelism. /// If all the global rules have no holes (i.e. we will have no grep patterns), we will try to find a match for each global rule in every file in the target. pub(crate) fn get_relevant_files( - &self, path_to_codebase: &str, include: &Vec, exclude: &Vec, + &self, paths_to_codebase: &Vec, include: &Vec, exclude: &Vec, ) -> HashMap { - let _path_to_codebase = Path::new(path_to_codebase).to_path_buf(); - - //If the path_to_codebase is a file, then execute piranha on it - if _path_to_codebase.is_file() { - return HashMap::from_iter([( - _path_to_codebase.clone(), - read_file(&_path_to_codebase).unwrap(), - )]); + let mut candidate_files: HashMap = HashMap::new(); + + for p2codebase in paths_to_codebase { + if !Path::new(p2codebase).exists() { + panic!("Path to codebase does not exist: {}", p2codebase); + } + let _paths_to_codebase = Path::new(p2codebase).to_path_buf(); + // If the path to codebase is a file, and the language can parse it, then add it to the files + if _paths_to_codebase.is_file() && self.language().can_parse(&_paths_to_codebase) { + candidate_files.insert( + _paths_to_codebase.clone(), + read_file(&_paths_to_codebase).unwrap(), + ); + continue; + } + candidate_files.extend(self.get_candidate_files_from_dir(p2codebase, include, exclude)); } - let mut files: HashMap = WalkDir::new(path_to_codebase) + // Filter the files based on the global rules with holes + let final_file_set = self.filter_files_based_on_global_rule_holes(candidate_files); + + debug!( + "{}", + format!("{} files will be analyzed.", final_file_set.len()).green() + ); + final_file_set + } + + // If there are global rules with holes (grep patterns containing placeholders), filter files to find matches for those patterns in the target. + // Otherwise, report all the files in the target. + fn filter_files_based_on_global_rule_holes( + &self, candidate_files: HashMap, + ) -> HashMap { + if self.any_global_rules_has_holes() { + let pattern = self.get_grep_heuristics(); + return candidate_files + .iter() + // Filter the files containing the desired regex pattern + .filter(|x| pattern.is_match(x.1.as_str())) + .map(|(x, y)| (x.clone(), y.clone())) + .collect(); + } + candidate_files + } + + /// Gets all the files from the code base that (i) have the language appropriate file extension, and (ii) satisfy include/exclude glob pattern + fn get_candidate_files_from_dir( + &self, p2codebase: &String, include: &Vec, exclude: &Vec, + ) -> HashMap { + let mut _files: HashMap = WalkDir::new(p2codebase) // walk over the entire code base .into_iter() // ignore errors @@ -165,24 +204,10 @@ impl RuleStore { // filter out all excluded paths (if any) .filter(|f| exclude.is_empty() || exclude.iter().all(|p| !p.matches_path(&f.path()))) // filter files with the desired extension - .filter(|de| self.language().can_parse(de)) + .filter(|de| self.language().can_parse(&de.path())) // read the file .map(|f| (f.path(), read_file(&f.path()).unwrap())) .collect(); - - if self.any_global_rules_has_holes() { - let pattern = self.get_grep_heuristics(); - files = files - .iter() - // Filter the files containing the desired regex pattern - .filter(|x| pattern.is_match(x.1.as_str())) - .map(|(x, y)| (x.clone(), y.clone())) - .collect(); - } - debug!( - "{}", - format!("{} files will be analyzed.", files.len()).green() - ); - files + _files } } diff --git a/src/models/unit_tests/piranha_arguments_test.rs b/src/models/unit_tests/piranha_arguments_test.rs index 8a80c989db..5516397ddc 100644 --- a/src/models/unit_tests/piranha_arguments_test.rs +++ b/src/models/unit_tests/piranha_arguments_test.rs @@ -35,7 +35,7 @@ fn piranha_argument_invalid_no_codebase_and_snippet() { fn piranha_argument_invalid_both_codebase_and_snippet() { let _ = PiranhaArgumentsBuilder::default() .path_to_configurations("some/path".to_string()) - .path_to_codebase("dev/null".to_string()) + .paths_to_codebase(vec!["dev/null".to_string()]) .code_snippet("class A { }".to_string()) .language(PiranhaLanguage::from(JAVA)) .substitutions(substitutions! {"super_interface_name" => "SomeInterface"}) diff --git a/src/models/unit_tests/rule_test.rs b/src/models/unit_tests/rule_test.rs index 55d4ba6a1d..1fdb94e47a 100644 --- a/src/models/unit_tests/rule_test.rs +++ b/src/models/unit_tests/rule_test.rs @@ -113,7 +113,7 @@ fn test_get_edit_positive_recursive() { let mut rule_store = RuleStore::default(); let args = PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .build(); let mut parser = args.language().parser(); @@ -173,7 +173,7 @@ fn test_get_edit_negative_recursive() { let mut rule_store = RuleStore::default(); let args = PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .build(); let mut parser = args.language().parser(); @@ -214,7 +214,7 @@ fn test_get_edit_for_context_positive() { let mut rule_store = RuleStore::default(); let args = PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .build(); let mut parser = args.language().parser(); @@ -255,7 +255,7 @@ fn test_get_edit_for_context_negative() { let mut rule_store = RuleStore::default(); let args = PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .build(); let mut parser = args.language().parser(); @@ -302,7 +302,7 @@ fn run_test_satisfies_filters_not_enclosing_node( let java = PiranhaLanguage::from(JAVA); let mut parser = java.parser(); let piranha_args = PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .language(java) .build(); let source_code_unit = SourceCodeUnit::new( diff --git a/src/models/unit_tests/source_code_unit_test.rs b/src/models/unit_tests/source_code_unit_test.rs index 57d549381b..402fe6326c 100644 --- a/src/models/unit_tests/source_code_unit_test.rs +++ b/src/models/unit_tests/source_code_unit_test.rs @@ -41,7 +41,7 @@ impl SourceCodeUnit { &HashMap::new(), PathBuf::new().as_path(), &PiranhaArgumentsBuilder::default() - .path_to_codebase("some/test/path/".to_string()) + .paths_to_codebase(vec!["some/test/path/".to_string()]) .language(PiranhaLanguage::from(language_name.as_str())) .build(), ) @@ -156,7 +156,7 @@ fn run_test_satisfies_filters( let java = get_java_tree_sitter_language(); let mut parser = java.parser(); let piranha_args = PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .language(java) .build(); let source_code_unit = SourceCodeUnit::new( @@ -316,7 +316,7 @@ fn test_satisfies_filters_not_contains_positive() { let java = get_java_tree_sitter_language(); let mut parser = java.parser(); let piranha_args = PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .language(java) .build(); let source_code_unit = SourceCodeUnit::new( @@ -381,7 +381,7 @@ fn test_satisfies_filters_not_contains_negative() { let java = get_java_tree_sitter_language(); let mut parser = java.parser(); let piranha_arguments = &PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .language(java) .build(); let source_code_unit = SourceCodeUnit::new( @@ -456,7 +456,7 @@ fn test_satisfies_filters_child_count() { let java = get_java_tree_sitter_language(); let mut parser = java.parser(); let piranha_arguments = &PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .language(java) .build(); let source_code_unit = SourceCodeUnit::new( @@ -527,7 +527,7 @@ fn test_satisfies_filters_sibling_count() { let java = get_java_tree_sitter_language(); let mut parser = java.parser(); let piranha_arguments = &PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .language(java) .build(); let source_code_unit = SourceCodeUnit::new( @@ -578,7 +578,7 @@ fn run_test_satisfies_filters_without_enclosing( let java = get_java_tree_sitter_language(); let mut parser = java.parser(); let piranha_args = PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .language(java) .build(); let source_code_unit = SourceCodeUnit::new( @@ -679,7 +679,7 @@ fn test_satisfies_outermost_enclosing_node() { let java = get_java_tree_sitter_language(); let mut parser = java.parser(); let piranha_arguments = &PiranhaArgumentsBuilder::default() - .path_to_codebase(UNUSED_CODE_PATH.to_string()) + .paths_to_codebase(vec![UNUSED_CODE_PATH.to_string()]) .language(java) .build(); let source_code_unit = SourceCodeUnit::new( diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 4a57fdd197..38dd843689 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -104,9 +104,8 @@ fn execute_piranha_and_check_result( piranha_arguments: &PiranhaArguments, path_to_expected: &Path, files_changed: usize, ignore_whitespace: bool, ) { - let path_to_codebase = Path::new(piranha_arguments.path_to_codebase()); + let path_to_codebase = Path::new(piranha_arguments.paths_to_codebase().first().unwrap()); let output_summaries = execute_piranha(piranha_arguments); - assert_eq!(output_summaries.len(), files_changed); let mut all_files_match = true; @@ -179,10 +178,10 @@ macro_rules! create_match_tests { fn $test_name() { super::initialize(); let _path= std::path::PathBuf::from("test-resources").join($language).join($path_to_test); - let path_to_codebase = _path.join("input").to_str().unwrap().to_string(); + let paths_to_codebase = vec![_path.join("input").to_str().unwrap().to_string()]; let path_to_configurations = _path.join("configurations").to_str().unwrap().to_string(); let piranha_arguments = $crate::models::piranha_arguments::PiranhaArgumentsBuilder::default() - .path_to_codebase(path_to_codebase) + .paths_to_codebase(paths_to_codebase) .path_to_configurations(path_to_configurations) .language($crate::models::language::PiranhaLanguage::from($language)) $( @@ -225,7 +224,7 @@ macro_rules! create_rewrite_tests { let temp_dir= super::copy_folder_to_temp_dir(&_path.join("input")); let piranha_arguments = $crate::models::piranha_arguments::PiranhaArgumentsBuilder::default() - .path_to_codebase(temp_dir.path().to_str().unwrap().to_string()) + .paths_to_codebase(vec![temp_dir.path().to_str().unwrap().to_string()]) .path_to_configurations(_path.join("configurations").to_str().unwrap().to_string()) .language($crate::models::language::PiranhaLanguage::from($language)) $( diff --git a/src/tests/test_piranha_java.rs b/src/tests/test_piranha_java.rs index 82387e9473..fcaaad0fa1 100644 --- a/src/tests/test_piranha_java.rs +++ b/src/tests/test_piranha_java.rs @@ -14,7 +14,7 @@ Copyright (c) 2023 Uber Technologies, Inc. use glob::Pattern; use super::{ - copy_folder_to_temp_dir, create_match_tests, create_rewrite_tests, + assert_frequency_for_matches, copy_folder_to_temp_dir, create_match_tests, create_rewrite_tests, execute_piranha_and_check_result, initialize, substitutions, }; use crate::{ @@ -97,7 +97,7 @@ fn test_delete_method_invocation_argument_invalid() { let path_to_codebase = _path.join("input").to_str().unwrap().to_string(); let path_to_configurations = _path.join("configurations").to_str().unwrap().to_string(); let piranha_arguments = PiranhaArgumentsBuilder::default() - .path_to_codebase(path_to_codebase) + .paths_to_codebase(vec![path_to_codebase]) .path_to_configurations(path_to_configurations) .language(PiranhaLanguage::from(JAVA)) .build(); @@ -117,7 +117,7 @@ fn test_scenarios_find_and_propagate_panic() { let path_to_codebase = _path.join("input").to_str().unwrap().to_string(); let path_to_configurations = _path.join("configurations").to_str().unwrap().to_string(); let piranha_arguments = PiranhaArgumentsBuilder::default() - .path_to_codebase(path_to_codebase) + .paths_to_codebase(vec![path_to_codebase]) .path_to_configurations(path_to_configurations) .language(PiranhaLanguage::from(JAVA)) .build(); @@ -135,7 +135,7 @@ fn test_scenarios_find_and_propagate_invalid_substitutions_panic() { let path_to_codebase = _path.join("input").to_str().unwrap().to_string(); let path_to_configurations = _path.join("configurations").to_str().unwrap().to_string(); let piranha_arguments = PiranhaArgumentsBuilder::default() - .path_to_codebase(path_to_codebase) + .paths_to_codebase(vec![path_to_codebase]) .path_to_configurations(path_to_configurations) .language(PiranhaLanguage::from(JAVA)) .substitutions(substitutions! {"super_interface_name" => "SomeInterface"}) @@ -207,7 +207,7 @@ fn _helper_user_option_delete_consecutive_lines( let temp_dir = copy_folder_to_temp_dir(&path_to_scenario.join("input")); let piranha_arguments = PiranhaArgumentsBuilder::default() - .path_to_codebase(temp_dir.path().to_str().unwrap().to_string()) + .paths_to_codebase(vec![temp_dir.path().to_str().unwrap().to_string()]) .path_to_configurations( path_to_scenario .join("configurations") @@ -292,7 +292,7 @@ fn test_consecutive_scope_level_rules() { }]; let args = PiranhaArgumentsBuilder::default() - .path_to_codebase(temp_dir.path().to_str().unwrap().to_string()) + .paths_to_codebase(vec![temp_dir.path().to_str().unwrap().to_string()]) .language(PiranhaLanguage::from(JAVA)) .rule_graph( RuleGraphBuilder::default() @@ -324,7 +324,7 @@ fn test_handle_syntactically_incorrect_tree() { }; let piranha_arguments = PiranhaArgumentsBuilder::default() - .path_to_codebase(temp_dir.path().to_str().unwrap().to_string()) + .paths_to_codebase(vec![temp_dir.path().to_str().unwrap().to_string()]) .language(PiranhaLanguage::from(JAVA)) .rule_graph(RuleGraphBuilder::default().rules(vec![rule]).build()) .allow_dirty_ast(true) @@ -356,7 +356,7 @@ fn test_do_not_allow_syntactically_incorrect_tree() { }; let piranha_arguments = PiranhaArgumentsBuilder::default() - .path_to_codebase(temp_dir.path().to_str().unwrap().to_string()) + .paths_to_codebase(vec![temp_dir.path().to_str().unwrap().to_string()]) .language(PiranhaLanguage::from(JAVA)) .rule_graph(RuleGraphBuilder::default().rules(vec![rule]).build()) .build(); @@ -388,7 +388,7 @@ fn test_handle_syntactically_incorrect_tree_panic() { }; let piranha_arguments = PiranhaArgumentsBuilder::default() - .path_to_codebase(temp_dir.path().to_str().unwrap().to_string()) + .paths_to_codebase(vec![temp_dir.path().to_str().unwrap().to_string()]) .language(PiranhaLanguage::from(JAVA)) .rule_graph(RuleGraphBuilder::default().rules(vec![rule]).build()) .build(); @@ -408,7 +408,7 @@ fn test_incorrect_rule() { let path_to_codebase = _path.join("input").to_str().unwrap().to_string(); let path_to_configurations = _path.join("configurations").to_str().unwrap().to_string(); let piranha_arguments = PiranhaArgumentsBuilder::default() - .path_to_codebase(path_to_codebase) + .paths_to_codebase(vec![path_to_codebase]) .path_to_configurations(path_to_configurations) .language(PiranhaLanguage::from(JAVA)) .build(); @@ -437,3 +437,26 @@ fn test_dyn_rule() { // assert assert_eq!(output_summaries.len(), 1); } + +#[test] + +fn test_multiple_code_bases() { + initialize(); + let _path = PathBuf::from("test-resources") + .join(JAVA) + .join("structural_find_replace_multiple_code_bases"); + let path_to_codebase1 = _path.join("folder_1").to_str().unwrap().to_string(); + let path_to_codebase2 = _path.join("folder_2").to_str().unwrap().to_string(); + let rule = piranha_rule! { + name = "match_import", + query = "cs import java.util.List;" + }; + let piranha_arguments = PiranhaArgumentsBuilder::default() + .language(PiranhaLanguage::from(JAVA)) + .paths_to_codebase(vec![path_to_codebase1, path_to_codebase2]) + .rule_graph(RuleGraphBuilder::default().rules(vec![rule]).build()) + .build(); + let output_summaries = execute_piranha(&piranha_arguments); + assert_eq!(output_summaries.len(), 2); + assert_frequency_for_matches(&output_summaries, &HashMap::from([("match_import", 2)])); +} diff --git a/src/tests/test_piranha_swift.rs b/src/tests/test_piranha_swift.rs index 697bfd8824..2615089d26 100644 --- a/src/tests/test_piranha_swift.rs +++ b/src/tests/test_piranha_swift.rs @@ -47,7 +47,7 @@ fn execute_piranha_with_default_swift_args(scenario: &str, substitutions: Vec<(S let _path = PathBuf::from("test-resources").join(SWIFT).join(scenario); let temp_dir = super::copy_folder_to_temp_dir(&_path.join("input")); let piranha_arguments = PiranhaArgumentsBuilder::default() - .path_to_codebase(temp_dir.path().to_str().unwrap().to_string()) + .paths_to_codebase(vec![temp_dir.path().to_str().unwrap().to_string()]) .path_to_configurations(_path.join("configurations").to_str().unwrap().to_string()) .language(PiranhaLanguage::from(SWIFT)) .cleanup_comments(true) diff --git a/test-resources/java/structural_find_replace_multiple_code_bases/folder_1/Sample.java b/test-resources/java/structural_find_replace_multiple_code_bases/folder_1/Sample.java new file mode 100644 index 0000000000..e0968be27e --- /dev/null +++ b/test-resources/java/structural_find_replace_multiple_code_bases/folder_1/Sample.java @@ -0,0 +1,3 @@ +package org.piranha.examples; + +import java.util.List; diff --git a/test-resources/java/structural_find_replace_multiple_code_bases/folder_2/Sample.java b/test-resources/java/structural_find_replace_multiple_code_bases/folder_2/Sample.java new file mode 100644 index 0000000000..e0968be27e --- /dev/null +++ b/test-resources/java/structural_find_replace_multiple_code_bases/folder_2/Sample.java @@ -0,0 +1,3 @@ +package org.piranha.examples; + +import java.util.List; diff --git a/test-resources/java/structural_find_replace_multiple_code_bases/folder_3/Sample.java b/test-resources/java/structural_find_replace_multiple_code_bases/folder_3/Sample.java new file mode 100644 index 0000000000..e0968be27e --- /dev/null +++ b/test-resources/java/structural_find_replace_multiple_code_bases/folder_3/Sample.java @@ -0,0 +1,3 @@ +package org.piranha.examples; + +import java.util.List;