use ll_sparql_parser::{SyntaxToken, parse_query, syntax_kind::SyntaxKind};
use crate::server::message_handler::completion::environment::CompletionLocation;
use super::{
get_anchor_token, get_continuations, get_following_token, get_location, get_trigger_token,
};
fn match_location_at_offset(input: &str, matcher: CompletionLocation, offset: u32) -> bool {
location(input, offset) == matcher
}
fn location(input: &str, offset: u32) -> CompletionLocation {
let (root, _) = parse_query(&input[..offset as usize]);
let trigger_token = get_trigger_token(&root, offset.into());
let anchor = trigger_token.and_then(get_anchor_token);
let continuations = get_continuations(&root, &anchor);
get_location(&anchor, &continuations, offset.into())
}
#[test]
fn find_anchor_path() {
let (root, _) = parse_query("Select * {?s ^}");
let trigger_token = get_trigger_token(&root, 14.into());
let anchor = trigger_token.and_then(get_anchor_token).unwrap();
assert_eq!(anchor.kind(), SyntaxKind::Zirkumflex)
}
#[test]
fn localize_select_binding() {
assert!(matches!(
location("Select ?a ? { )}", 11),
CompletionLocation::SelectBinding(_),
));
assert!(matches!(
location("Select {}", 7),
CompletionLocation::SelectBinding(_),
));
assert!(!matches!(
location("Select Reduced ?a {}", 0),
CompletionLocation::SelectBinding(_),
));
assert!(matches!(
location("Select Reduced ?a {}", 14),
CompletionLocation::SelectBinding(_),
));
assert!(matches!(
location("Select Reduced ?a {}", 17),
CompletionLocation::SelectBinding(_),
));
assert!(matches!(
location("Select Reduced ?a {}", 16),
CompletionLocation::SelectBinding(_),
));
assert!(matches!(
location("Select * {}", 8),
CompletionLocation::SelectBinding(_),
));
assert!(matches!(
location("Select (3 as ?x) {}", 16),
CompletionLocation::SelectBinding(_),
));
assert!(!matches!(
location("Select * { BIND (42 AS )}", 23),
CompletionLocation::SelectBinding(_),
));
}
#[test]
fn localize_blank_property() {
let input = "Select * { ?s ?p [] }";
assert!(matches!(
location(input, 18),
CompletionLocation::BlankNodeProperty(_),
));
}
#[test]
fn localize_start_1() {
let input = "\n";
assert!(match_location_at_offset(
input,
CompletionLocation::Start,
0
));
}
#[test]
fn localize_start_2() {
let input = "S\n";
assert!(match_location_at_offset(
input,
CompletionLocation::Start,
1
));
}
#[test]
fn localize_solution_modifier() {
let input = "Select * {} \n";
assert!(match_location_at_offset(
input,
CompletionLocation::SolutionModifier,
12
));
}
#[test]
fn localize_subject_1() {
let input = "Select * { }";
assert!(match_location_at_offset(
input,
CompletionLocation::Subject,
11
));
}
#[test]
fn localize_subject_2() {
let input = "Select * { ?s ?p ?o . }";
assert!(match_location_at_offset(
input,
CompletionLocation::Subject,
21
));
}
#[test]
fn localize_subject_3() {
let input = "Select * { ?s ?p ?o . ?s ?p ?o }";
assert!(match_location_at_offset(
input,
CompletionLocation::Subject,
22
));
}
#[test]
fn localize_subject_4() {
let input = "Select * { ? }";
assert!(match_location_at_offset(
input,
CompletionLocation::Subject,
12
));
}
#[test]
fn localize_subject_5() {
let input = "Select * { ?var }";
assert!(match_location_at_offset(
input,
CompletionLocation::Subject,
15
));
}
#[test]
fn localize_predicate_1() {
let input = "Select * { ?a }";
assert!(matches!(
location(input, 14),
CompletionLocation::Predicate(_),
));
}
#[test]
fn localize_predicate_2() {
let input = "Select * { <iri> }";
assert!(matches!(
location(input, 17),
CompletionLocation::Predicate(_),
));
}
#[test]
fn localize_predicate_3() {
let input = "Select * { \"str\" }";
assert!(matches!(
location(input, 17),
CompletionLocation::Predicate(_),
));
}
#[test]
fn localize_predicate_4() {
let input = "Select * { ?a ?b ?c ; }";
assert!(matches!(
location(input, 21),
CompletionLocation::Predicate(_),
));
}
#[test]
fn localize_predicate_5() {
let input = "Select * { ?a a }";
assert!(matches!(
location(input, 15),
CompletionLocation::Predicate(_),
));
}
#[test]
fn localize_object_1() {
let input = "Select * { ?a ?b }";
assert!(matches!(location(input, 17), CompletionLocation::Object(_)));
}
#[test]
fn localize_object_2() {
let input = "Select * { ?a <iri> }";
assert!(matches!(location(input, 20), CompletionLocation::Object(_)));
}
#[test]
fn localize_object_3() {
let input = "Select * { ?a ?a ?b, }";
assert!(matches!(location(input, 21), CompletionLocation::Object(_)));
}
#[test]
fn localize_object_4() {
let input = "Select * { ?a rdfs:label ? }";
assert!(matches!(location(input, 26), CompletionLocation::Object(_)));
}
fn trigger_token_at(input: &str, offset: u32) -> Option<SyntaxToken> {
let (root, _) = parse_query(input);
get_trigger_token(&root, offset.into())
}
#[test]
fn trigger_token_at_end() {
let input = "Select * { ?a ?a ?b }";
assert!(matches!(
trigger_token_at(input, 21).unwrap().kind(),
SyntaxKind::RCurly
));
}
#[test]
fn localize_a() {
let input = "Select * { ?a a }";
assert!(matches!(location(input, 16), CompletionLocation::Object(_),));
}
#[test]
fn localize_order_condition() {
let input = "SELECT * WHERE {} ORDER BY ";
let (root, _) = parse_query(input);
assert!(get_trigger_token(&root, 27.into()).is_some());
}
#[test]
fn localize_group_condition_after_group_by() {
let input = "SELECT * WHERE {} GROUP BY ";
assert!(matches!(
location(input, 27),
CompletionLocation::GroupCondition(_)
));
}
#[test]
fn localize_group_condition_partial_variable() {
let input = "SELECT * WHERE {} GROUP BY ?v";
assert!(matches!(
location(input, 29),
CompletionLocation::GroupCondition(_)
));
}
#[test]
fn localize_group_condition_bracketted_expression() {
let input = "SELECT * WHERE {} GROUP BY (";
assert!(matches!(
location(input, 28),
CompletionLocation::GroupCondition(_)
));
}
#[test]
fn localize_group_condition_does_not_shadow_order_condition() {
let input = "SELECT * WHERE {} GROUP BY ?a ORDER BY ";
assert!(matches!(
location(input, 39),
CompletionLocation::OrderCondition
));
}
#[test]
fn localize_inline_data_one_var() {
let input = "SELECT * { VALUES ?x { } }";
assert!(matches!(
location(input, 23),
CompletionLocation::InlineData((_, 0)),
));
}
#[test]
fn localize_inline_data_one_var_with_existing_value() {
let input = "SELECT * { VALUES ?x { <a> } }";
assert!(matches!(
location(input, 27),
CompletionLocation::InlineData((_, 0)),
));
}
#[test]
fn localize_inline_data_full_first_slot() {
let input = "SELECT * { VALUES (?x ?y) { ( ) } }";
assert!(matches!(
location(input, 30),
CompletionLocation::InlineData((_, 0)),
));
}
#[test]
fn localize_inline_data_full_second_slot() {
let input = "SELECT * { VALUES (?x ?y) { (<a> ) } }";
assert!(matches!(
location(input, 33),
CompletionLocation::InlineData((_, 1)),
));
}
#[test]
fn localize_inline_data_full_third_slot() {
let input = "SELECT * { VALUES (?x ?y ?z) { (<a> <b> ) } }";
assert!(matches!(
location(input, 40),
CompletionLocation::InlineData((_, 2)),
));
}
#[test]
fn localize_inline_data_full_second_row_resets_index() {
let input = "SELECT * { VALUES (?x ?y) { (<a> <b>) ( ) } }";
assert!(matches!(
location(input, 40),
CompletionLocation::InlineData((_, 0)),
));
}
#[test]
fn localize_inline_data_full_second_row_second_slot() {
let input = "SELECT * { VALUES (?x ?y) { (<a> <b>) (<c> ) } }";
assert!(matches!(
location(input, 44),
CompletionLocation::InlineData((_, 1)),
));
}
#[test]
fn localize_inline_data_empty_multi_var_block_is_unknown() {
let input = "SELECT * { VALUES (?x ?y) { } }";
assert!(matches!(location(input, 28), CompletionLocation::Unknown));
}
#[test]
fn localize_inline_data_post_query_is_unknown() {
let input = "SELECT * {} VALUES ?x { }";
assert!(matches!(location(input, 24), CompletionLocation::Unknown));
}
#[test]
fn localize_inline_data_full_no_space_after_lparen() {
let input = "SELECT * { VALUES (?x ?y) { (|) } }";
assert!(matches!(
location(input, 29),
CompletionLocation::InlineData((_, 0)),
));
}
#[test]
fn localize_inline_data_index_beyond_declared_vars() {
let input = "SELECT * { VALUES (?x ?y) { (<a> <b> |) } }";
assert!(matches!(
location(input, 38),
CompletionLocation::InlineData((_, 2)),
));
}
fn following_kind(input: &str, offset: u32) -> Option<SyntaxKind> {
let (root, _) = parse_query(input);
get_following_token(&root, offset.into()).map(|token| token.kind())
}
#[test]
fn following_token_is_dot() {
assert_eq!(
following_kind("Select * {?s ?p ?o .}", 18),
Some(SyntaxKind::Dot)
);
}
#[test]
fn following_token_is_semicolon() {
assert_eq!(
following_kind("Select * {?s ?p ?o ;}", 18),
Some(SyntaxKind::Semicolon)
);
}
#[test]
fn following_token_skips_comment_before_dot() {
let input = "Select * {?s ?p ?o # comment\n.}";
assert_eq!(following_kind(input, 18), Some(SyntaxKind::Dot));
}
#[test]
fn following_token_without_terminator() {
assert_eq!(
following_kind("Select * {?s ?p ?o }", 18),
Some(SyntaxKind::RCurly)
);
}