mod common;
use common::sqry_bin;
use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use tempfile::TempDir;
fn create_test_project(files: &[(&str, &str)]) -> TempDir {
let dir = TempDir::new().unwrap();
for (path, content) in files {
let file_path = dir.path().join(path);
fs::create_dir_all(file_path.parent().unwrap()).unwrap();
fs::write(&file_path, content).unwrap();
}
dir
}
fn sqry_cmd() -> Command {
let path = sqry_bin();
Command::new(path)
}
#[test]
fn test_unmatched_parenthesis_error() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("(kind:function AND name:test")
.arg(project.path())
.assert()
.failure()
.code(2) .stderr(predicate::str::contains("sqry::parse"))
.stderr(predicate::str::contains("Unmatched opening parenthesis"))
.stderr(predicate::str::contains("(kind:function AND name:test"));
}
#[test]
fn test_unterminated_string_error() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg(r#"kind:function AND name:"test"#)
.arg(project.path())
.assert()
.failure()
.code(2)
.stderr(predicate::str::contains("sqry::")) .stderr(predicate::str::contains("Unterminated string"))
.stderr(predicate::str::contains(r#"kind:function AND name:"test"#));
}
#[test]
fn test_unterminated_regex_error() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("kind:function AND name~=/test")
.arg(project.path())
.assert()
.failure()
.code(2)
.stderr(predicate::str::contains("sqry::")) .stderr(predicate::str::contains("Unterminated regex"))
.stderr(predicate::str::contains("kind:function AND name~=/test"));
}
#[test]
fn test_unknown_field_with_suggestion() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("kind:function AND knd:test")
.arg(project.path())
.assert()
.failure()
.code(2)
.stderr(predicate::str::contains("sqry::validation"))
.stderr(predicate::str::contains("Unknown field 'knd'"))
.stderr(predicate::str::contains("Did you mean 'kind'?"))
.stderr(predicate::str::contains("kind:function AND knd:test"))
.stderr(predicate::str::contains(
"unknown field, did you mean 'kind'?",
))
.stderr(predicate::str::contains("Use 'sqry query --help'"));
}
#[test]
fn test_invalid_enum_value() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("kind:invalid_kind")
.arg(project.path())
.assert()
.failure()
.code(2)
.stderr(predicate::str::contains("sqry::validation"))
.stderr(predicate::str::contains(
"Invalid value 'invalid_kind' for field 'kind'",
))
.stderr(predicate::str::contains("kind:invalid_kind"))
.stderr(predicate::str::contains("invalid enum value"))
.stderr(predicate::str::contains("Valid values:"))
.stderr(predicate::str::contains("function"))
.stderr(predicate::str::contains("method"))
.stderr(predicate::str::contains("class"));
}
#[test]
fn test_unknown_field_no_suggestion() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("kind:function AND xyz:test")
.arg(project.path())
.assert()
.failure()
.code(2)
.stderr(predicate::str::contains("sqry::validation"))
.stderr(predicate::str::contains("Unknown field 'xyz'"))
.stderr(predicate::str::contains("kind:function AND xyz:test"))
.stderr(predicate::str::contains("unknown field"));
}
#[test]
fn test_nested_parenthesis_error() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("kind:function AND (name:test OR (name:foo)")
.arg(project.path())
.assert()
.failure()
.code(2)
.stderr(predicate::str::contains("sqry::parse"))
.stderr(predicate::str::contains("Unmatched opening parenthesis"));
}
#[test]
fn test_multiple_boolean_operators_with_error() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("kind:function OR knd:method AND async:true")
.arg(project.path())
.assert()
.failure()
.code(2)
.stderr(predicate::str::contains("sqry::validation"))
.stderr(predicate::str::contains("Unknown field 'knd'"));
}
#[test]
fn test_error_contains_unicode_box_drawing() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("(kind:function")
.arg(project.path())
.assert()
.failure()
.code(2)
.stderr(predicate::str::contains("×")) .stderr(predicate::str::contains("│")) .stderr(predicate::str::contains("╭")) .stderr(predicate::str::contains("╰")); }
#[test]
fn test_parse_error_exit_code() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("(kind:function")
.arg(project.path())
.assert()
.failure()
.code(2); }
#[test]
fn test_validation_error_exit_code() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("kind:function AND knd:test") .arg(project.path())
.assert()
.failure()
.code(2); }
#[test]
fn test_error_span_points_to_correct_location() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
sqry_cmd()
.arg("query")
.arg("kind:function AND knd:test")
.arg(project.path())
.assert()
.failure()
.stderr(predicate::str::contains("position 18")); }
#[test]
fn test_error_shows_full_query_context() {
let project = create_test_project(&[("test.rs", "fn test() {}")]);
let query = "kind:function AND name:test AND invalid_field:value";
sqry_cmd()
.arg("query")
.arg(query)
.arg(project.path())
.assert()
.failure()
.stderr(predicate::str::contains(query)); }