use super::*;
use tree_sitter::{Parser, QueryCursor, StreamingIterator};
fn parse(source: &str) -> tree_sitter::Tree {
let mut parser = Parser::new();
parser.set_language(&perl_language()).unwrap();
parser.parse(source, None).unwrap()
}
#[test]
fn test_cpanfile_requires_cached() {
let q1 = cpanfile_requires();
let q2 = cpanfile_requires();
assert!(std::ptr::eq(q1, q2), "Should return same cached query");
}
#[test]
fn test_cpanfile_requires_matches() {
let source = "requires 'DBI';\nrequires 'JSON', '>= 2.0';";
let tree = parse(source);
let query = cpanfile_requires();
let module_idx = query.capture_index_for_name("module").unwrap();
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(query, tree.root_node(), source.as_bytes());
let mut modules = Vec::new();
while let Some(m) = matches.next() {
for cap in m.captures {
if cap.index == module_idx {
modules.push(cap.node.utf8_text(source.as_bytes()).unwrap().to_string());
}
}
}
assert_eq!(modules, vec!["DBI", "JSON"]);
}
#[test]
fn test_exports_qw_matches() {
let source = r#"
our @EXPORT_OK = qw(alpha beta gamma);
our @EXPORT = qw(delta);
"#;
let tree = parse(source);
let query = exports_qw();
let var_idx = query.capture_index_for_name("var").unwrap();
let words_idx = query.capture_index_for_name("words").unwrap();
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(query, tree.root_node(), source.as_bytes());
let mut results: Vec<(String, Vec<String>)> = Vec::new();
while let Some(m) = matches.next() {
let mut var_name = String::new();
let mut words = Vec::new();
for cap in m.captures {
let text = cap.node.utf8_text(source.as_bytes()).unwrap();
if cap.index == var_idx {
var_name = text.to_string();
} else if cap.index == words_idx {
words.extend(text.split_whitespace().map(String::from));
}
}
if !var_name.is_empty() {
results.push((var_name, words));
}
}
assert_eq!(results.len(), 2);
assert_eq!(results[0].0, "@EXPORT_OK");
assert_eq!(results[0].1, vec!["alpha", "beta", "gamma"]);
assert_eq!(results[1].0, "@EXPORT");
assert_eq!(results[1].1, vec!["delta"]);
}
#[test]
fn test_exports_paren_list_matches() {
let source = r#"
our @EXPORT_OK = ('foo', 'bar', 'baz');
"#;
let tree = parse(source);
let query = exports_paren_list();
let var_idx = query.capture_index_for_name("var").unwrap();
let word_idx = query.capture_index_for_name("word").unwrap();
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(query, tree.root_node(), source.as_bytes());
let mut var_name = String::new();
let mut words = Vec::new();
while let Some(m) = matches.next() {
for cap in m.captures {
let text = cap.node.utf8_text(source.as_bytes()).unwrap();
if cap.index == var_idx && var_name.is_empty() {
var_name = text.to_string();
} else if cap.index == word_idx {
words.push(text.to_string());
}
}
}
assert_eq!(var_name, "@EXPORT_OK");
assert_eq!(words, vec!["foo", "bar", "baz"]);
}
#[test]
fn test_exports_paren_list_single_element() {
let source = "our @EXPORT_OK = ('single');\n";
let tree = parse(source);
let query = exports_paren_list();
let word_idx = query.capture_index_for_name("word").unwrap();
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(query, tree.root_node(), source.as_bytes());
let mut words = Vec::new();
while let Some(m) = matches.next() {
for cap in m.captures {
if cap.index == word_idx {
words.push(cap.node.utf8_text(source.as_bytes()).unwrap().to_string());
}
}
}
assert_eq!(words, vec!["single"]);
}
#[test]
fn test_exports_qw_no_our() {
let source = "@EXPORT = qw(no_our);\n";
let tree = parse(source);
let query = exports_qw();
let var_idx = query.capture_index_for_name("var").unwrap();
let words_idx = query.capture_index_for_name("words").unwrap();
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(query, tree.root_node(), source.as_bytes());
let mut var_name = String::new();
let mut words = Vec::new();
while let Some(m) = matches.next() {
for cap in m.captures {
let text = cap.node.utf8_text(source.as_bytes()).unwrap();
if cap.index == var_idx {
var_name = text.to_string();
} else if cap.index == words_idx {
words.extend(text.split_whitespace().map(String::from));
}
}
}
assert_eq!(var_name, "@EXPORT");
assert_eq!(words, vec!["no_our"]);
}
#[test]
fn test_exports_qw_inside_parens() {
let source = "our @EXPORT = (qw/lolz this is nested/);\n";
let tree = parse(source);
let query = exports_qw();
let words_idx = query.capture_index_for_name("words").unwrap();
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(query, tree.root_node(), source.as_bytes());
let mut words = Vec::new();
while let Some(m) = matches.next() {
for cap in m.captures {
if cap.index == words_idx {
words.extend(
cap.node
.utf8_text(source.as_bytes())
.unwrap()
.split_whitespace()
.map(String::from),
);
}
}
}
assert_eq!(words, vec!["lolz", "this", "is", "nested"]);
}
#[test]
fn test_exports_mixed_strings_and_qw() {
let source = "our @EXPORT_OK = ('now', 'what', qw/man this is stuffs/);\n";
let tree = parse(source);
let root = tree.root_node();
let bytes = source.as_bytes();
let qw = exports_qw();
let qw_words_idx = qw.capture_index_for_name("words").unwrap();
let mut cursor1 = QueryCursor::new();
let mut matches1 = cursor1.matches(qw, root, bytes);
let mut all_words = Vec::new();
while let Some(m) = matches1.next() {
for cap in m.captures {
if cap.index == qw_words_idx {
all_words.extend(
cap.node
.utf8_text(bytes)
.unwrap()
.split_whitespace()
.map(String::from),
);
}
}
}
let pl = exports_paren_list();
let pl_word_idx = pl.capture_index_for_name("word").unwrap();
let mut cursor2 = QueryCursor::new();
let mut matches2 = cursor2.matches(pl, root, bytes);
while let Some(m) = matches2.next() {
for cap in m.captures {
if cap.index == pl_word_idx {
all_words.push(cap.node.utf8_text(bytes).unwrap().to_string());
}
}
}
all_words.sort();
assert_eq!(
all_words,
vec!["is", "man", "now", "stuffs", "this", "what"]
);
}
#[test]
fn test_exports_empty_qw() {
let source = "our @EXPORT = qw();\n";
let tree = parse(source);
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(exports_qw(), tree.root_node(), source.as_bytes());
assert!(
matches.next().is_none(),
"empty qw should produce no matches"
);
}
#[test]
fn test_exports_empty_parens() {
let source = "our @EXPORT_OK = ();\n";
let tree = parse(source);
let mut cursor1 = QueryCursor::new();
let mut matches1 = cursor1.matches(exports_qw(), tree.root_node(), source.as_bytes());
assert!(matches1.next().is_none());
let mut cursor2 = QueryCursor::new();
let mut matches2 = cursor2.matches(exports_paren_list(), tree.root_node(), source.as_bytes());
assert!(matches2.next().is_none());
}