mod common;
use common::sqry_bin;
use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::TempDir;
#[test]
fn cli_java_exports_classes_and_methods() {
let project = TempDir::new().unwrap();
let java_code = r"
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
private void validate() {
// private method
}
}
";
std::fs::write(project.path().join("User.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("exports:User")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("User.java"));
Command::new(sqry_bin())
.arg("query")
.arg("exports:getName")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("User.java"));
Command::new(sqry_bin())
.arg("query")
.arg("exports:validate")
.arg(project.path())
.assert()
.success()
.stderr(predicate::str::contains("No matches found"));
}
#[test]
fn cli_java_exports_interfaces() {
let project = TempDir::new().unwrap();
let java_code = r"
public interface Repository<T> {
void save(T item);
T findById(int id);
void delete(int id);
}
public class UserRepository implements Repository<User> {
public void save(User user) {
// implementation
}
public User findById(int id) {
return null;
}
public void delete(int id) {
// implementation
}
}
class User {
String name;
}
";
std::fs::write(project.path().join("Repository.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("exports:Repository")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("Repository.java"));
Command::new(sqry_bin())
.arg("query")
.arg("exports:UserRepository")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("Repository.java"));
}
#[test]
fn cli_java_callers_method_calls() {
let project = TempDir::new().unwrap();
let java_code = r#"
public class Processor {
private boolean validate(String input) {
return input != null && input.length() > 0;
}
public String process(String data) {
if (validate(data)) {
return data.trim();
}
return null;
}
public static void main(String[] args) {
Processor p = new Processor();
p.process("test");
}
}
"#;
std::fs::write(project.path().join("Processor.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:validate")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("process"));
Command::new(sqry_bin())
.arg("query")
.arg("callers:process")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("main"));
}
#[test]
fn cli_java_callers_static_method_calls() {
let project = TempDir::new().unwrap();
let java_code = r"
public class MathUtils {
public static int add(int a, int b) {
return a + b;
}
public static int multiply(int a, int b) {
return a * b;
}
public static int calculate(int x, int y) {
int sum = add(x, y);
int product = multiply(x, y);
return sum + product;
}
public static void main(String[] args) {
int result = calculate(2, 3);
System.out.println(result);
}
}
";
std::fs::write(project.path().join("MathUtils.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:add")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("calculate"));
Command::new(sqry_bin())
.arg("query")
.arg("callers:multiply")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("calculate"));
}
#[test]
fn cli_java_callers_chained_method_calls() {
let project = TempDir::new().unwrap();
let java_code = r#"
public class QueryBuilder {
private String condition;
private String field;
private int limit;
public QueryBuilder where(String condition) {
this.condition = condition;
return this;
}
public QueryBuilder orderBy(String field) {
this.field = field;
return this;
}
public QueryBuilder limit(int count) {
this.limit = count;
return this;
}
public Object[] execute() {
return new Object[0];
}
public static void main(String[] args) {
runQuery();
}
private static Object[] runQuery() {
return new QueryBuilder()
.where("active = true")
.orderBy("created_at")
.limit(10)
.execute();
}
}
"#;
std::fs::write(project.path().join("QueryBuilder.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:where")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("runQuery"));
Command::new(sqry_bin())
.arg("query")
.arg("callers:execute")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("runQuery"));
}
#[test]
fn cli_java_callees_method() {
let project = TempDir::new().unwrap();
let java_code = r#"
public class Logger {
private void log(String message) {
System.out.println(message);
}
private void warn(String message) {
System.out.println("WARNING: " + message);
}
public void handleError(Exception error) {
log("Error occurred");
warn(error.getMessage());
System.err.println(error.getStackTrace());
}
public static void main(String[] args) {
Logger logger = new Logger();
logger.handleError(new Exception("Test"));
}
}
"#;
std::fs::write(project.path().join("Logger.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callees:handleError")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("log"))
.stdout(predicate::str::contains("warn"));
}
#[test]
fn cli_java_callees_with_inheritance() {
let project = TempDir::new().unwrap();
let java_code = r#"
class UserService {
protected User findUser(int id) {
return new User(id, "Test");
}
protected boolean validateUser(User user) {
return user.getId() > 0;
}
public User getUser(int id) {
User user = findUser(id);
if (validateUser(user)) {
return user;
}
return null;
}
}
class User {
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
}
"#;
std::fs::write(project.path().join("UserService.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callees:getUser")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("findUser"))
.stdout(predicate::str::contains("validateUser"));
}
#[test]
fn cli_java_imports() {
let project = TempDir::new().unwrap();
let java_code = r"
import java.util.List;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;
public class FileProcessor {
private List<String> files;
public FileProcessor() {
files = new ArrayList<>();
}
public void processFile(String path) throws IOException {
File file = new File(path);
// process file
}
}
";
std::fs::write(project.path().join("FileProcessor.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("imports:List")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("FileProcessor.java"));
Command::new(sqry_bin())
.arg("query")
.arg("imports:ArrayList")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("FileProcessor.java"));
}
#[test]
fn cli_java_generics() {
let project = TempDir::new().unwrap();
let java_code = r"
public class DataService<T> {
private T data;
public void setData(T data) {
this.data = data;
}
public T getData() {
return data;
}
public T process(T input) {
validate(input);
return transform(input);
}
private void validate(T input) {
// validation
}
private T transform(T input) {
return input;
}
}
";
std::fs::write(project.path().join("DataService.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callees:process")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("validate"))
.stdout(predicate::str::contains("transform"));
}
#[test]
fn cli_java_private_methods() {
let project = TempDir::new().unwrap();
let java_code = r"
public class Service {
public void execute() {
validate();
}
private void validate() {
// private method
}
}
";
std::fs::write(project.path().join("Service.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:validate")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("execute"));
}
#[test]
fn cli_java_callers_no_results() {
let project = TempDir::new().unwrap();
let java_code = r#"
public class Unused {
private int unusedMethod() {
return 42;
}
public static void main(String[] args) {
System.out.println("Hello");
}
}
"#;
std::fs::write(project.path().join("Unused.java"), java_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:unusedMethod")
.arg(project.path())
.assert()
.success();
}