mod common;
use common::sqry_bin;
use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::TempDir;
#[test]
fn cli_javascript_exports_es6_named_exports() {
let project = TempDir::new().unwrap();
let js_code = r#"
export function greet(name) {
return `Hello, ${name}!`;
}
export function farewell(name) {
return `Goodbye, ${name}!`;
}
export class User {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
export const API_VERSION = "1.0.0";
function internalHelper() {
return true;
}
"#;
std::fs::write(project.path().join("module.js"), js_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("exports:greet")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("module.js"));
Command::new(sqry_bin())
.arg("query")
.arg("exports:User")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("module.js"));
Command::new(sqry_bin())
.arg("query")
.arg("exports:internalHelper")
.arg(project.path())
.assert()
.success()
.stderr(predicate::str::contains("No matches found"));
}
#[test]
fn cli_javascript_exports_default_export() {
let project = TempDir::new().unwrap();
let js_code = r"
export default class Application {
constructor(config) {
this.config = config;
}
run() {
console.log('App running');
}
}
";
std::fs::write(project.path().join("app.js"), js_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("exports:Application")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("app.js"));
}
#[test]
fn cli_javascript_exports_commonjs() {
let project = TempDir::new().unwrap();
let js_code = r"
function helper(x) {
return x * 2;
}
function calculate(a, b) {
return helper(a) + helper(b);
}
module.exports = {
helper,
calculate
};
";
std::fs::write(project.path().join("utils.js"), js_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("exports:helper")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("utils.js"));
Command::new(sqry_bin())
.arg("query")
.arg("exports:calculate")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("utils.js"));
}
#[test]
fn cli_javascript_callers_function_calls() {
let project = TempDir::new().unwrap();
let js_code = r#"
function validate(input) {
return input.length > 0;
}
function process(data) {
if (validate(data)) {
return data.trim();
}
return null;
}
process("test");
"#;
std::fs::write(project.path().join("processor.js"), js_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"));
}
#[test]
fn cli_javascript_callers_method_calls() {
let project = TempDir::new().unwrap();
let js_code = r"
class DataService {
fetchData() {
return [];
}
transformData(data) {
return data.map(x => x * 2);
}
process() {
const data = this.fetchData();
return this.transformData(data);
}
}
const service = new DataService();
service.process();
";
std::fs::write(project.path().join("service.js"), js_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:fetchData")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("process"));
Command::new(sqry_bin())
.arg("query")
.arg("callers:transformData")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("process"));
}
#[test]
fn cli_javascript_callers_chained_methods() {
let project = TempDir::new().unwrap();
let js_code = r"
class QueryBuilder {
where(condition) {
return this;
}
orderBy(field) {
return this;
}
limit(count) {
return this;
}
execute() {
return [];
}
}
function runQuery() {
return new QueryBuilder()
.where('active = true')
.orderBy('created_at')
.limit(10)
.execute();
}
runQuery();
";
std::fs::write(project.path().join("query.js"), js_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_javascript_callees_function() {
let project = TempDir::new().unwrap();
let js_code = r"
function log(message) {
console.log(message);
}
function warn(message) {
console.warn(message);
}
function handleError(error) {
log('Error occurred');
warn(error.message);
console.error(error.stack);
}
handleError(new Error('Test'));
";
std::fs::write(project.path().join("logger.js"), js_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_javascript_callees_method() {
let project = TempDir::new().unwrap();
let js_code = r"
class UserService {
findUser(id) {
return { id, name: 'Test' };
}
validateUser(user) {
return user.id > 0;
}
getUser(id) {
const user = this.findUser(id);
if (this.validateUser(user)) {
return user;
}
return null;
}
}
const service = new UserService();
service.getUser(1);
";
std::fs::write(project.path().join("user-service.js"), js_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_javascript_imports_es6_imports() {
let project = TempDir::new().unwrap();
let js_code = r"
import { greet, farewell } from './utils';
import User from './user';
import * as helpers from './helpers';
function main() {
const user = new User('Alice');
greet(user.getName());
helpers.process();
}
main();
";
std::fs::write(project.path().join("main.js"), js_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("imports:user")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("main.js"));
Command::new(sqry_bin())
.arg("query")
.arg("imports:utils")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("main.js"));
}
#[test]
fn cli_javascript_imports_commonjs_require() {
let project = TempDir::new().unwrap();
let js_code = r"
const fs = require('fs');
const path = require('path');
const { helper } = require('./utils');
function readConfig() {
const configPath = path.join(__dirname, 'config.json');
return fs.readFileSync(configPath, 'utf8');
}
readConfig();
";
std::fs::write(project.path().join("config.js"), js_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("imports:fs")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("config.js"));
}
#[test]
fn cli_javascript_arrow_functions() {
let project = TempDir::new().unwrap();
let js_code = r"
const double = (x) => x * 2;
const triple = (x) => x * 3;
const calculate = (value) => {
const d = double(value);
const t = triple(value);
return d + t;
};
export { double, triple, calculate };
";
std::fs::write(project.path().join("math.js"), js_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("exports:double")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("math.js"));
Command::new(sqry_bin())
.arg("query")
.arg("callers:double")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("calculate"));
}
#[test]
fn cli_javascript_async_await() {
let project = TempDir::new().unwrap();
let js_code = r"
async function fetchUser(id) {
return { id, name: 'Test' };
}
async function fetchPosts(userId) {
return [];
}
async function getUserData(id) {
const user = await fetchUser(id);
const posts = await fetchPosts(user.id);
return { user, posts };
}
getUserData(1);
";
std::fs::write(project.path().join("async.js"), js_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callees:getUserData")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("fetchUser"))
.stdout(predicate::str::contains("fetchPosts"));
}
#[test]
fn cli_javascript_exports_private_functions_not_exported() {
let project = TempDir::new().unwrap();
let js_code = r"
function privateHelper() {
return 42;
}
export function publicAPI() {
return privateHelper();
}
";
std::fs::write(project.path().join("api.js"), js_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("exports:publicAPI")
.arg(project.path())
.assert()
.success()
.stdout(predicate::str::contains("api.js"));
}
#[test]
fn cli_javascript_callers_no_results() {
let project = TempDir::new().unwrap();
let js_code = r"
function unusedFunction() {
return 42;
}
function main() {
console.log('Hello');
}
main();
";
std::fs::write(project.path().join("unused.js"), js_code).unwrap();
Command::new(sqry_bin())
.arg("index")
.arg(project.path())
.assert()
.success();
Command::new(sqry_bin())
.arg("query")
.arg("callers:unusedFunction")
.arg(project.path())
.assert()
.success();
}