diff --git a/src/lib.rs b/src/lib.rs index 27e8c3f..b79434b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,7 @@ pub enum LogError { /// Collection of log statements in a single source file #[derive(Debug)] pub struct StatementsInFile { - pub filename: String, + pub path: String, id: SourceFileID, pub log_statements: Vec, /// A single matcher for all log statements. @@ -113,14 +113,24 @@ impl LogMatcher { } /// Check if the given path is covered by any of the roots in this matcher. - pub fn match_path(&self, path: &Path) -> Option { + pub fn match_path(&self, path: &Path) -> Option<(&PathBuf, &SourceTree)> { self.roots .iter() .filter(|(existing_path, _coll)| path.starts_with(existing_path)) - .map(|(path, _coll)| path.clone()) .next() } + pub fn find_source_file_statements(&self, path: &Path) -> Option<&StatementsInFile> { + if let Some((_root_path, src_tree)) = self.match_path(path) { + src_tree + .tree + .find_file(path) + .and_then(|info| src_tree.files_with_statements.get(&info.id)) + } else { + None + } + } + /// Traverse the roots looking for supported source files. #[must_use] pub fn discover_sources(&mut self, tracker: &ProgressTracker) -> Vec { @@ -197,7 +207,7 @@ impl LogMatcher { // XXX this block and the else are basically the same, try to refactor coll.files_with_statements .values() - .filter(|stmts| stmts.filename.contains(filename)) + .filter(|stmts| stmts.path.contains(filename)) .flat_map(|stmts| { let file_matches = stmts.matcher.matches(body); match file_matches.iter().next() { @@ -231,7 +241,7 @@ impl LogMatcher { } } -#[derive(Debug, PartialEq, Copy, Clone, Serialize)] +#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize)] pub enum SourceLanguage { Rust, Java, @@ -254,6 +264,14 @@ const IDENTS_JAVA: &[&str] = &["logger", "log", "fine", "debug", "info", "warn", const IDENTS_CPP: &[&str] = &["debug", "info", "warn", "trace"]; impl SourceLanguage { + pub fn as_str(&self) -> &'static str { + match self { + SourceLanguage::Rust => "Rust", + SourceLanguage::Java => "Java", + SourceLanguage::Cpp => "C++", + } + } + fn from_extension(extension: &OsStr) -> Option { match extension.to_str() { Some("rs") => Some(Self::Rust), @@ -288,12 +306,11 @@ impl SourceLanguage { (method_invocation object: (identifier) @object-name name: (identifier) @method-name - arguments: (argument_list [ - (_ (string_literal) @log (_ (this)? @this (identifier) @arguments)) - (_ (string_literal (_ (this)? @this (identifier) @arguments)) @log) - (string_literal) @log (this)? @this (identifier) @arguments - (string_literal) @log (this)? @this - ]) + arguments: [ + (argument_list (template_expression + template_argument: (string_literal) @arguments)) + (argument_list (string_literal) @arguments) + ] (#match? @object-name "log(ger)?|LOG(GER)?") (#match? @method-name "fine|debug|info|warn|trace") ) @@ -490,7 +507,7 @@ pub fn extract_logging(sources: &[CodeSource], tracker: &ProgressTracker) -> Vec matched.push(src_ref); } } - "identifier" | "this" => { + "args" | "this" => { if !matched.is_empty() { let range = result.range; let source = code.buffer.as_str(); @@ -506,6 +523,7 @@ pub fn extract_logging(sources: &[CodeSource], tracker: &ProgressTracker) -> Vec { let length = matched.len() - 1; let prior_result: &mut SourceRef = matched.get_mut(length).unwrap(); + prior_result.end_line_no = result.range.end_point.row + 1; prior_result.vars.push(text.trim().to_string()); } } @@ -519,7 +537,7 @@ pub fn extract_logging(sources: &[CodeSource], tracker: &ProgressTracker) -> Vec None } else { Some(StatementsInFile { - filename: matched.first().unwrap().source_path.clone(), + path: matched.first().unwrap().source_path.clone(), id: code.info.id, log_statements: matched, matcher: RegexSet::new(patterns).expect("To combine patterns"), diff --git a/src/snapshots/log2src__source_hier__test__with_resources_dir-3.snap b/src/snapshots/log2src__source_hier__test__with_resources_dir-3.snap index 21a3ad9..6e37b1b 100644 --- a/src/snapshots/log2src__source_hier__test__with_resources_dir-3.snap +++ b/src/snapshots/log2src__source_hier__test__with_resources_dir-3.snap @@ -7,12 +7,12 @@ expression: new_and_updated_events - 1 - DeletedFile: - test_java.rs - - 5 + - 6 - NewFile: - Basic.java - language: Java - id: 7 + id: 8 - NewFile: - new.rs - language: Rust - id: 8 + id: 9 diff --git a/src/snapshots/log2src__source_hier__test__with_resources_dir-4.snap b/src/snapshots/log2src__source_hier__test__with_resources_dir-4.snap index 74e7e3d..1ea48bf 100644 --- a/src/snapshots/log2src__source_hier__test__with_resources_dir-4.snap +++ b/src/snapshots/log2src__source_hier__test__with_resources_dir-4.snap @@ -4,13 +4,16 @@ expression: deleted_dir_events --- - DeletedFile: - BasicWithUpper.java - - 4 + - 5 - DeletedFile: - BasicWithLog.java - - 3 + - 4 - DeletedFile: - BasicWithCustom.java + - 3 +- DeletedFile: + - BasicSlf4j.java - 2 - DeletedFile: - Basic.java - - 7 + - 8 diff --git a/src/snapshots/log2src__source_hier__test__with_resources_dir.snap b/src/snapshots/log2src__source_hier__test__with_resources_dir.snap index 8b16bcc..72fdd7e 100644 --- a/src/snapshots/log2src__source_hier__test__with_resources_dir.snap +++ b/src/snapshots/log2src__source_hier__test__with_resources_dir.snap @@ -5,21 +5,25 @@ expression: events - NewFile: - test_rust.rs - language: Rust - id: 6 + id: 7 - NewFile: - test_java.rs - language: Rust - id: 5 + id: 6 - NewFile: - BasicWithUpper.java - language: Java - id: 4 + id: 5 - NewFile: - BasicWithLog.java - language: Java - id: 3 + id: 4 - NewFile: - BasicWithCustom.java + - language: Java + id: 3 +- NewFile: + - BasicSlf4j.java - language: Java id: 2 - NewFile: diff --git a/src/source_hier.rs b/src/source_hier.rs index 0134fa0..bf7e7d3 100644 --- a/src/source_hier.rs +++ b/src/source_hier.rs @@ -3,10 +3,14 @@ use serde::Serialize; use std::cell::RefCell; use std::collections::BTreeMap; use std::ffi::{OsStr, OsString}; -use std::path::{Path, PathBuf}; +use std::path::{Component, Path, PathBuf}; use std::time::SystemTime; use std::{fs, io}; +fn is_ignored_dir(name: &OsStr) -> bool { + name == ".git" || name == ".hg" || name == ".svn" || name == ".vscode" +} + /// Result of a shallow check of a file system path. Mainly interested in getting a directory /// listing without descending into the child trees. enum ShallowCheckResult { @@ -24,7 +28,7 @@ enum ShallowCheckResult { pub struct SourceFileID(usize); /// A summary of a source code file -#[derive(Copy, Clone, Debug, Serialize)] +#[derive(Copy, Clone, Debug, Serialize, Eq, PartialEq)] pub struct SourceFileInfo { pub language: SourceLanguage, pub id: SourceFileID, @@ -80,6 +84,7 @@ impl SourceHierContent { Ok(entries) => Self::Directory { entries: entries .into_iter() + .filter(|entry| !is_ignored_dir(&entry.0)) .map(|(entry_name, meta)| { ( entry_name.to_os_string(), @@ -210,7 +215,8 @@ impl SourceHierContent { let mut new_entries: Vec<(OsString, Result)> = Vec::new(); for (name, meta) in latest_entries { - if let Some(existing_entry) = entries.get_mut(&name) { + if is_ignored_dir(&name.as_os_str()) { + } else if let Some(existing_entry) = entries.get_mut(&name) { existing_entry.sync(&path.join(&name), meta, deleted_events) } else { new_entries.push((name, meta)); @@ -229,6 +235,24 @@ impl SourceHierContent { }; true } + + pub fn find_file(&self, self_path: &Path, desired_path: &Path) -> Option { + match self { + SourceHierContent::File { info, .. } if desired_path == Path::new("") => Some(*info), + SourceHierContent::Directory { ref entries } => { + let mut components = desired_path.components(); + if let Some(Component::Normal(name)) = components.next() { + if let Some(node) = entries.get(name) { + return node + .content + .find_file(&self_path.join(name), components.as_path()); + } + } + None + } + _ => None, + } + } } /// A node in the SourceHierTree. It contains information that is common to all types of content @@ -432,6 +456,13 @@ impl SourceHierTree { } } + pub fn find_file(&self, path: &Path) -> Option { + match path.strip_prefix(&self.root_path) { + Ok(sub_path) => self.root_node.content.find_file(&self.root_path, sub_path), + Err(_) => None, + } + } + /// Visit every node in the hierarchy, depth-first, calling `f` on each. pub fn visit(&self, mut f: F) where @@ -468,17 +499,16 @@ impl SourceHierTree { #[cfg(test)] mod test { - use crate::source_hier::{ScanEvent, SourceHierTree}; + use crate::source_hier::{ScanEvent, SourceFileID, SourceFileInfo, SourceHierTree}; + use crate::SourceLanguage; use fs_extra::dir::copy; use fs_extra::dir::CopyOptions; use insta::assert_yaml_snapshot; use std::fs; use std::fs::File; use std::io::Write; - use std::ops::Sub; use std::path::Path; use std::path::PathBuf; - use std::time::{Duration, SystemTime}; use tempfile::{tempdir, TempDir}; fn setup_test_environment(source_dir: &Path) -> TempDir { @@ -511,6 +541,10 @@ mod test { fn test_with_resources_dir() { let tests_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); let temp_test_dir = setup_test_environment(&tests_path); + let _ = fs::create_dir(temp_test_dir.path().join(".git")).unwrap(); + let _ = File::create_new(temp_test_dir.path().join(".git/config")) + .unwrap().write("abc".as_bytes()) + .unwrap(); let basic_path = temp_test_dir.path().join("tests/java/Basic.java"); { let metadata = fs::metadata(&basic_path).unwrap(); @@ -522,6 +556,14 @@ mod test { tree.sync(); let events: Vec = tree.scan().map(redact_event).collect(); assert_yaml_snapshot!(events); + let find_res = tree.find_file(&basic_path); + assert_eq!( + find_res, + Some(SourceFileInfo { + language: SourceLanguage::Java, + id: SourceFileID(1) + }) + ); let no_events: Vec = tree.scan().map(redact_event).collect(); assert_yaml_snapshot!(no_events); let _ = fs::remove_file(temp_test_dir.path().join("tests/test_java.rs")).unwrap(); diff --git a/src/source_query.rs b/src/source_query.rs index 412cfea..24eb0d0 100644 --- a/src/source_query.rs +++ b/src/source_query.rs @@ -1,5 +1,4 @@ use std::ops::Range; - use tree_sitter::{ Language, Node, Parser, Point, Query, QueryCursor, Range as TSRange, StreamingIterator, Tree, }; @@ -42,8 +41,16 @@ impl<'a> SourceQuery<'a> { let mut results = Vec::new(); let matches = cursor.matches(&query, self.tree.root_node(), self.source.as_bytes()); matches.for_each(|m| { + let mut got_string_literal = false; for capture in m.captures { let mut child = capture.node; + if child.kind() == "string_literal" { + // only return results after the format string literal, other captures + // are not relevant. + got_string_literal = true; + } else if !got_string_literal { + continue; + } let mut arg_start: Option<(usize, Point)> = None; if filter_idx.is_none() || filter_idx.is_some_and(|f| f == capture.index) { @@ -52,24 +59,24 @@ impl<'a> SourceQuery<'a> { range: capture.node.range(), name_range: Self::find_fn_range(child), }); - } - while let Some(next_child) = child.next_sibling() { - if matches!(next_child.kind(), "," | ")") { - if let Some(start) = arg_start { - results.push(QueryResult { - kind: "identifier".to_string(), - range: TSRange { - start_byte: start.0, - start_point: start.1, - end_byte: next_child.start_byte(), - end_point: next_child.start_position(), - }, - name_range: Self::find_fn_range(child), - }); + while let Some(next_child) = child.next_sibling() { + if matches!(next_child.kind(), "," | ")") { + if let Some(start) = arg_start { + results.push(QueryResult { + kind: "args".to_string(), + range: TSRange { + start_byte: start.0, + start_point: start.1, + end_byte: next_child.start_byte(), + end_point: next_child.start_position(), + }, + name_range: Self::find_fn_range(child), + }); + } + arg_start = Some((next_child.end_byte(), next_child.end_position())); } - arg_start = Some((next_child.end_byte(), next_child.end_position())); + child = next_child; } - child = next_child; } } }); diff --git a/src/source_ref.rs b/src/source_ref.rs index d8677aa..7193573 100644 --- a/src/source_ref.rs +++ b/src/source_ref.rs @@ -20,6 +20,8 @@ pub struct SourceRef { pub language: SourceLanguage, #[serde(rename(serialize = "lineNumber"))] pub line_no: usize, + #[serde(rename(serialize = "endLineNumber"))] + pub end_line_no: usize, pub column: usize, pub name: String, pub text: String, @@ -35,7 +37,8 @@ impl SourceRef { let range = result.range; let source = code.buffer.as_str(); let text = source[range.start_byte..range.end_byte].to_string(); - let line = range.start_point.row + 1; + let line_no = range.start_point.row + 1; + let end_line_no = range.end_point.row + 1; let col = range.start_point.column; let start = range.start_byte + 1; let mut end = range.end_byte - 1; @@ -49,7 +52,8 @@ impl SourceRef { Some(SourceRef { source_path: code.filename.clone(), language: code.info.language, - line_no: line, + line_no, + end_line_no, column: col, name, text, @@ -93,7 +97,7 @@ static RUST_PLACEHOLDER_REGEX: LazyLock = LazyLock::new(|| { }); static JAVA_PLACEHOLDER_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r#"\\?\{.*}"#).unwrap()); + LazyLock::new(|| Regex::new(r#"\{.*}|\\\{(.*)}"#).unwrap()); static CPP_PLACEHOLDER_REGEX: LazyLock = LazyLock::new(|| Regex::new(r#"%[-+ #0]*\d*(?:\.\d+)?[hlLzjt]*[diuoxXfFeEgGaAcspn%]|\{(?:([a-zA-Z_][a-zA-Z0-9_.]*)|(\d+))?\s*(?::[^}]*)?}"#).unwrap()); @@ -112,7 +116,7 @@ fn build_matcher( ) -> Option<(Regex, String, Vec)> { let mut args = Vec::new(); let mut last_end = 0; - let mut pattern = "^".to_string(); + let mut pattern = "(?s)^".to_string(); let mut exact_len = 0; for cap in placeholder_regex_for(language).captures_iter(text) { let placeholder = cap.get(0).unwrap(); @@ -165,7 +169,7 @@ mod tests { fn test_build_matcher_needs_escape() { let (matcher, _pat, _args) = build_matcher("{}) {}, {}", SourceLanguage::Rust).unwrap(); assert_eq!( - Regex::new(r#"^(.+)\) (.+), (.+)$"#).unwrap().as_str(), + Regex::new(r#"(?s)^(.+)\) (.+), (.+)$"#).unwrap().as_str(), matcher.as_str() ); } @@ -175,7 +179,7 @@ mod tests { let (matcher, _pat, _args) = build_matcher("abc {main_path:?} def", SourceLanguage::Rust).unwrap(); assert_eq!( - Regex::new(r#"^abc (.+) def$"#).unwrap().as_str(), + Regex::new(r#"(?s)^abc (.+) def$"#).unwrap().as_str(), matcher.as_str() ); } @@ -185,7 +189,7 @@ mod tests { let (matcher, _pat, args) = build_matcher("{}) {:?}, {foo.bar}", SourceLanguage::Rust).unwrap(); assert_eq!( - Regex::new(r#"^(.+)\) (.+), (.+)$"#).unwrap().as_str(), + Regex::new(r#"(?s)^(.+)\) (.+), (.+)$"#).unwrap().as_str(), matcher.as_str() ); assert_eq!(args[2], FormatArgument::Named("foo.bar".to_string())); @@ -195,7 +199,7 @@ mod tests { fn test_build_matcher_positional() { let (matcher, _pat, args) = build_matcher("second={2}", SourceLanguage::Rust).unwrap(); assert_eq!( - Regex::new(r#"^second=(.+)$"#).unwrap().as_str(), + Regex::new(r#"(?s)^second=(.+)$"#).unwrap().as_str(), matcher.as_str() ); assert_eq!(args[0], FormatArgument::Positional(2)); @@ -206,7 +210,7 @@ mod tests { let (matcher, _pat, args) = build_matcher("they are %d years old", SourceLanguage::Cpp).unwrap(); assert_eq!( - Regex::new(r#"^they are (.+) years old$"#).unwrap().as_str(), + Regex::new(r#"(?s)^they are (.+) years old$"#).unwrap().as_str(), matcher.as_str() ); assert_eq!(args[0], FormatArgument::Placeholder); @@ -217,7 +221,7 @@ mod tests { let (matcher, _pat, args) = build_matcher("they are {0:d} years old", SourceLanguage::Cpp).unwrap(); assert_eq!( - Regex::new(r#"^they are (.+) years old$"#).unwrap().as_str(), + Regex::new(r#"(?s)^they are (.+) years old$"#).unwrap().as_str(), matcher.as_str() ); assert_eq!(args[0], FormatArgument::Positional(0)); @@ -237,7 +241,7 @@ mod tests { ) .unwrap(); assert_eq!( - Regex::new(r#"^you're only as funky\n as your last cut$"#) + Regex::new(r#"(?s)^you're only as funky\n as your last cut$"#) .unwrap() .as_str(), matcher.as_str() diff --git a/tests/java/BasicSlf4j.java b/tests/java/BasicSlf4j.java new file mode 100644 index 0000000..b5e6564 --- /dev/null +++ b/tests/java/BasicSlf4j.java @@ -0,0 +1,15 @@ +package org.example; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Main { + private static final Logger logger = LoggerFactory.getLogger(Main.class); + + public static void main(String[] args) throws InterruptedException { + logger.info("Application starting"); + + logger.debug("Debug message: args length = {}", + args.length); + } +} diff --git a/tests/resources/java/basic-slf4j.log b/tests/resources/java/basic-slf4j.log new file mode 100644 index 0000000..fffe4be --- /dev/null +++ b/tests/resources/java/basic-slf4j.log @@ -0,0 +1,2 @@ +2024-05-08 14:46:47 Application starting +2024-05-08 14:46:47 Debug message: args length = 0 diff --git a/tests/snapshots/test_java__basic.snap b/tests/snapshots/test_java__basic.snap index 6bf5d0a..4da36ad 100644 --- a/tests/snapshots/test_java__basic.snap +++ b/tests/snapshots/test_java__basic.snap @@ -13,9 +13,9 @@ info: success: true exit_code: 0 ----- stdout ----- -{"srcRef":{"sourcePath":"{java_dir}/Basic.java","language":"Java","lineNumber":18,"column":16,"name":"main","text":"\"Hello from main\"","pattern":"^Hello from main$","args":[],"vars":[]},"variables":[]} -{"srcRef":{"sourcePath":"{java_dir}/Basic.java","language":"Java","lineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"0"}]} -{"srcRef":{"sourcePath":"{java_dir}/Basic.java","language":"Java","lineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"1"}]} -{"srcRef":{"sourcePath":"{java_dir}/Basic.java","language":"Java","lineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"2"}]} +{"srcRef":{"sourcePath":"{java_dir}/Basic.java","language":"Java","lineNumber":18,"endLineNumber":18,"column":16,"name":"main","text":"\"Hello from main\"","pattern":"(?s)^Hello from main$","args":[],"vars":[]},"variables":[]} +{"srcRef":{"sourcePath":"{java_dir}/Basic.java","language":"Java","lineNumber":25,"endLineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"0"}]} +{"srcRef":{"sourcePath":"{java_dir}/Basic.java","language":"Java","lineNumber":25,"endLineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"1"}]} +{"srcRef":{"sourcePath":"{java_dir}/Basic.java","language":"Java","lineNumber":25,"endLineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"2"}]} ----- stderr ----- diff --git a/tests/snapshots/test_java__basic_slf4j.snap b/tests/snapshots/test_java__basic_slf4j.snap new file mode 100644 index 0000000..49e612e --- /dev/null +++ b/tests/snapshots/test_java__basic_slf4j.snap @@ -0,0 +1,19 @@ +--- +source: tests/test_java.rs +info: + program: log2src + args: + - "-d" + - tests/java/BasicSlf4j.java + - "-l" + - tests/resources/java/basic-slf4j.log + - "-f" + - "^(?\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}) (?.*)$" +--- +success: true +exit_code: 0 +----- stdout ----- +{"srcRef":{"sourcePath":"{java_dir}/BasicSlf4j.java","language":"Java","lineNumber":10,"endLineNumber":10,"column":20,"name":"main","text":"\"Application starting\"","pattern":"(?s)^Application starting$","args":[],"vars":[]},"variables":[]} +{"srcRef":{"sourcePath":"{java_dir}/BasicSlf4j.java","language":"Java","lineNumber":12,"endLineNumber":13,"column":21,"name":"main","text":"\"Debug message: args length = {}\"","pattern":"(?s)^Debug message: args length = (.+)$","args":["Placeholder"],"vars":["args.length"]},"variables":[{"expr":"args.length","value":"0"}]} + +----- stderr ----- diff --git a/tests/snapshots/test_java__basic_with_log.snap b/tests/snapshots/test_java__basic_with_log.snap index 6eb7996..82589d2 100644 --- a/tests/snapshots/test_java__basic_with_log.snap +++ b/tests/snapshots/test_java__basic_with_log.snap @@ -13,9 +13,9 @@ info: success: true exit_code: 0 ----- stdout ----- -{"srcRef":{"sourcePath":"{java_dir}/BasicWithLog.java","language":"Java","lineNumber":18,"column":13,"name":"main","text":"\"Hello from main\"","pattern":"^Hello from main$","args":[],"vars":[]},"variables":[]} -{"srcRef":{"sourcePath":"{java_dir}/BasicWithLog.java","language":"Java","lineNumber":25,"column":17,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"0"}]} -{"srcRef":{"sourcePath":"{java_dir}/BasicWithLog.java","language":"Java","lineNumber":25,"column":17,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"1"}]} -{"srcRef":{"sourcePath":"{java_dir}/BasicWithLog.java","language":"Java","lineNumber":25,"column":17,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"2"}]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithLog.java","language":"Java","lineNumber":18,"endLineNumber":18,"column":13,"name":"main","text":"\"Hello from main\"","pattern":"(?s)^Hello from main$","args":[],"vars":[]},"variables":[]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithLog.java","language":"Java","lineNumber":25,"endLineNumber":25,"column":17,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"0"}]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithLog.java","language":"Java","lineNumber":25,"endLineNumber":25,"column":17,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"1"}]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithLog.java","language":"Java","lineNumber":25,"endLineNumber":25,"column":17,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"2"}]} ----- stderr ----- diff --git a/tests/snapshots/test_java__basic_with_log_format.snap b/tests/snapshots/test_java__basic_with_log_format.snap index 84ea199..938011f 100644 --- a/tests/snapshots/test_java__basic_with_log_format.snap +++ b/tests/snapshots/test_java__basic_with_log_format.snap @@ -13,9 +13,9 @@ info: success: true exit_code: 0 ----- stdout ----- -{"srcRef":{"sourcePath":"{java_dir}/BasicWithCustom.java","language":"Java","lineNumber":15,"column":16,"name":"main","text":"\"Hello from main\"","pattern":"^Hello from main$","args":[],"vars":[]},"variables":[]} -{"srcRef":{"sourcePath":"{java_dir}/BasicWithCustom.java","language":"Java","lineNumber":22,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"0"}]} -{"srcRef":{"sourcePath":"{java_dir}/BasicWithCustom.java","language":"Java","lineNumber":22,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"1"}]} -{"srcRef":{"sourcePath":"{java_dir}/BasicWithCustom.java","language":"Java","lineNumber":22,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"2"}]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithCustom.java","language":"Java","lineNumber":15,"endLineNumber":15,"column":16,"name":"main","text":"\"Hello from main\"","pattern":"(?s)^Hello from main$","args":[],"vars":[]},"variables":[]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithCustom.java","language":"Java","lineNumber":22,"endLineNumber":22,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"0"}]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithCustom.java","language":"Java","lineNumber":22,"endLineNumber":22,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"1"}]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithCustom.java","language":"Java","lineNumber":22,"endLineNumber":22,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"2"}]} ----- stderr ----- diff --git a/tests/snapshots/test_java__basic_with_upper.snap b/tests/snapshots/test_java__basic_with_upper.snap index cfd8b44..873670b 100644 --- a/tests/snapshots/test_java__basic_with_upper.snap +++ b/tests/snapshots/test_java__basic_with_upper.snap @@ -13,9 +13,9 @@ info: success: true exit_code: 0 ----- stdout ----- -{"srcRef":{"sourcePath":"{java_dir}/BasicWithUpper.java","language":"Java","lineNumber":18,"column":16,"name":"main","text":"\"Hello from main\"","pattern":"^Hello from main$","args":[],"vars":[]},"variables":[]} -{"srcRef":{"sourcePath":"{java_dir}/BasicWithUpper.java","language":"Java","lineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"0"}]} -{"srcRef":{"sourcePath":"{java_dir}/BasicWithUpper.java","language":"Java","lineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"1"}]} -{"srcRef":{"sourcePath":"{java_dir}/BasicWithUpper.java","language":"Java","lineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"2"}]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithUpper.java","language":"Java","lineNumber":18,"endLineNumber":18,"column":16,"name":"main","text":"\"Hello from main\"","pattern":"(?s)^Hello from main$","args":[],"vars":[]},"variables":[]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithUpper.java","language":"Java","lineNumber":25,"endLineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"0"}]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithUpper.java","language":"Java","lineNumber":25,"endLineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"1"}]} +{"srcRef":{"sourcePath":"{java_dir}/BasicWithUpper.java","language":"Java","lineNumber":25,"endLineNumber":25,"column":20,"name":"foo","text":"\"Hello from foo i=\\{i}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":[{"Named":"i"}],"vars":[]},"variables":[{"expr":"i","value":"2"}]} ----- stderr ----- diff --git a/tests/snapshots/test_rust__basic.snap b/tests/snapshots/test_rust__basic.snap index 925c230..78b0c43 100644 --- a/tests/snapshots/test_rust__basic.snap +++ b/tests/snapshots/test_rust__basic.snap @@ -13,11 +13,11 @@ info: success: true exit_code: 0 ----- stdout ----- -{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":6,"column":11,"name":"main","text":"\"Hello from main\"","pattern":"^Hello from main$","args":[],"vars":[]},"variables":[]} -{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":15,"column":11,"name":"foo","text":"\"Hello from foo i={}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"0"}]} -{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":15,"column":11,"name":"foo","text":"\"Hello from foo i={}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"1"}]} -{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":15,"column":11,"name":"foo","text":"\"Hello from foo i={}\"","pattern":"^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"2"}]} -{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":18,"column":24,"name":"bar","text":"\"Hello from bar j={j}\"","pattern":"^Hello from bar j=(.+)$","args":[{"Named":"j"}],"vars":[]},"variables":[{"expr":"j","value":"4"}]} -{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":20,"column":32,"name":"baz","text":"\"Hello from baz i={1} j={0}\"","pattern":"^Hello from baz i=(.+) j=(.+)$","args":[{"Positional":1},{"Positional":0}],"vars":["j","i"]},"variables":[{"expr":"i","value":"5"},{"expr":"j","value":"6"}]} +{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":6,"endLineNumber":6,"column":11,"name":"main","text":"\"Hello from main\"","pattern":"(?s)^Hello from main$","args":[],"vars":[]},"variables":[]} +{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":15,"endLineNumber":15,"column":11,"name":"foo","text":"\"Hello from foo i={}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"0"}]} +{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":15,"endLineNumber":15,"column":11,"name":"foo","text":"\"Hello from foo i={}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"1"}]} +{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":15,"endLineNumber":15,"column":11,"name":"foo","text":"\"Hello from foo i={}\"","pattern":"(?s)^Hello from foo i=(.+)$","args":["Placeholder"],"vars":["i"]},"variables":[{"expr":"i","value":"2"}]} +{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":18,"endLineNumber":18,"column":24,"name":"bar","text":"\"Hello from bar j={j}\"","pattern":"(?s)^Hello from bar j=(.+)$","args":[{"Named":"j"}],"vars":[]},"variables":[{"expr":"j","value":"4"}]} +{"srcRef":{"sourcePath":"{example_dir}/basic.rs","language":"Rust","lineNumber":20,"endLineNumber":20,"column":32,"name":"baz","text":"\"Hello from baz i={1} j={0}\"","pattern":"(?s)^Hello from baz i=(.+) j=(.+)$","args":[{"Positional":1},{"Positional":0}],"vars":["j","i"]},"variables":[{"expr":"i","value":"5"},{"expr":"j","value":"6"}]} ----- stderr ----- diff --git a/tests/snapshots/test_rust__stack.snap b/tests/snapshots/test_rust__stack.snap index e579659..9d5c58e 100644 --- a/tests/snapshots/test_rust__stack.snap +++ b/tests/snapshots/test_rust__stack.snap @@ -15,6 +15,6 @@ info: success: true exit_code: 0 ----- stdout ----- -{"srcRef":{"sourcePath":"{example_dir}/stack.rs","language":"Rust","lineNumber":15,"column":11,"name":"b","text":"\"Hello from b\"","pattern":"^Hello from b$","args":[],"vars":[]},"variables":[]} +{"srcRef":{"sourcePath":"{example_dir}/stack.rs","language":"Rust","lineNumber":15,"endLineNumber":15,"column":11,"name":"b","text":"\"Hello from b\"","pattern":"(?s)^Hello from b$","args":[],"vars":[]},"variables":[]} ----- stderr ----- diff --git a/tests/test_java.rs b/tests/test_java.rs index 2a726ff..3b8507e 100644 --- a/tests/test_java.rs +++ b/tests/test_java.rs @@ -83,3 +83,23 @@ fn basic_with_log_format() -> Result<(), Box> { assert_cmd_snapshot!(cmd); Ok(()) } + +#[test] +fn basic_slf4j() -> Result<(), Box> { + let _guard = common_settings::enable_filters(); + let mut cmd = Command::cargo_bin("log2src")?; + let source = Path::new("tests").join("java").join("BasicSlf4j.java"); + let log = Path::new("tests") + .join("resources") + .join("java") + .join("basic-slf4j.log"); + cmd.arg("-d") + .arg(source.to_str().expect("test case source code exists")) + .arg("-l") + .arg(log.to_str().expect("test case log exists")) + .arg("-f") + .arg("^(?\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}) (?.*)$"); + + assert_cmd_snapshot!(cmd); + Ok(()) +}