use crate::core::{Position, Span};
use crate::semantic::adapters::selection::find_kerml_selection_spans;
use crate::syntax::kerml::ast::{Element, Feature, FeatureDirection, FeatureMember, KerMLFile};
use crate::syntax::kerml::model::types::Comment;
fn make_span(start_line: usize, start_col: usize, end_line: usize, end_col: usize) -> Span {
Span {
start: Position {
line: start_line,
column: start_col,
},
end: Position {
line: end_line,
column: end_col,
},
}
}
fn make_feature_with_span(name: &str, span: Option<Span>) -> Feature {
Feature {
name: Some(name.to_string()),
direction: None,
is_const: false,
is_derived: false,
body: vec![],
span,
}
}
fn make_feature_with_body(name: &str, span: Option<Span>, body: Vec<FeatureMember>) -> Feature {
Feature {
name: Some(name.to_string()),
direction: None,
is_const: false,
is_derived: false,
body,
span,
}
}
#[test]
fn test_feature_with_span_containing_position() {
let feature = make_feature_with_span("testFeature", Some(make_span(1, 0, 3, 1)));
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(2, 5); let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 1);
assert_eq!(spans[0].start.line, 1);
assert_eq!(spans[0].end.line, 3);
}
#[test]
fn test_feature_with_span_not_containing_position() {
let feature = make_feature_with_span("testFeature", Some(make_span(1, 0, 3, 1)));
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(5, 5); let spans = find_kerml_selection_spans(&file, pos);
assert!(spans.is_empty());
}
#[test]
fn test_feature_with_no_span() {
let feature = make_feature_with_span("testFeature", None);
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(2, 5);
let spans = find_kerml_selection_spans(&file, pos);
assert!(spans.is_empty());
}
#[test]
fn test_feature_with_empty_body() {
let feature = make_feature_with_span("emptyFeature", Some(make_span(1, 0, 2, 1)));
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(1, 5); let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 1);
assert_eq!(spans[0].start.line, 1);
}
#[test]
fn test_feature_with_comment_in_body_containing_position() {
let comment = Comment {
content: "Test comment".to_string(),
about: vec![],
locale: None,
span: Some(make_span(2, 2, 2, 20)),
};
let feature = make_feature_with_body(
"featureWithComment",
Some(make_span(1, 0, 3, 1)),
vec![FeatureMember::Comment(comment)],
);
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(2, 10); let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 2);
assert_eq!(spans[0].start.line, 2);
assert_eq!(spans[0].end.line, 2);
assert_eq!(spans[1].start.line, 1);
assert_eq!(spans[1].end.line, 3);
}
#[test]
fn test_feature_with_comment_in_body_not_containing_position() {
let comment = Comment {
content: "Test comment".to_string(),
about: vec![],
locale: None,
span: Some(make_span(2, 2, 2, 20)),
};
let feature = make_feature_with_body(
"featureWithComment",
Some(make_span(1, 0, 4, 1)),
vec![FeatureMember::Comment(comment)],
);
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(3, 5); let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 1);
assert_eq!(spans[0].start.line, 1);
assert_eq!(spans[0].end.line, 4);
}
#[test]
fn test_feature_with_multiple_comments() {
let comment1 = Comment {
content: "First comment".to_string(),
about: vec![],
locale: None,
span: Some(make_span(2, 2, 2, 20)),
};
let comment2 = Comment {
content: "Second comment".to_string(),
about: vec![],
locale: None,
span: Some(make_span(3, 2, 3, 25)),
};
let feature = make_feature_with_body(
"featureWithComments",
Some(make_span(1, 0, 4, 1)),
vec![
FeatureMember::Comment(comment1),
FeatureMember::Comment(comment2),
],
);
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(3, 10);
let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 2);
assert_eq!(spans[0].start.line, 3); assert_eq!(spans[1].start.line, 1); }
#[test]
fn test_feature_with_comment_with_no_span() {
let comment = Comment {
content: "Comment without span".to_string(),
about: vec![],
locale: None,
span: None,
};
let feature = make_feature_with_body(
"featureWithComment",
Some(make_span(1, 0, 3, 1)),
vec![FeatureMember::Comment(comment)],
);
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(2, 5);
let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 1);
assert_eq!(spans[0].start.line, 1);
}
#[test]
fn test_feature_with_different_directions() {
let feature_in = Feature {
name: Some("inputFeature".to_string()),
direction: Some(FeatureDirection::In),
is_const: false,
is_derived: false,
body: vec![],
span: Some(make_span(1, 0, 2, 1)),
};
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature_in)],
};
let pos = Position::new(1, 5);
let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 1);
assert_eq!(spans[0].start.line, 1);
}
#[test]
fn test_feature_readonly_and_derived() {
let feature = Feature {
name: Some("readonlyFeature".to_string()),
direction: None,
is_const: true,
is_derived: true,
body: vec![],
span: Some(make_span(1, 0, 2, 1)),
};
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(1, 5);
let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 1);
assert_eq!(spans[0].start.line, 1);
}
#[test]
fn test_feature_at_span_boundary_start() {
let feature = make_feature_with_span("boundaryFeature", Some(make_span(5, 10, 7, 20)));
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(5, 10); let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 1);
}
#[test]
fn test_feature_at_span_boundary_end() {
let feature = make_feature_with_span("boundaryFeature", Some(make_span(5, 10, 7, 20)));
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(7, 20); let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 1);
}
#[test]
fn test_feature_just_before_span() {
let feature = make_feature_with_span("beforeFeature", Some(make_span(5, 10, 7, 20)));
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(5, 9); let spans = find_kerml_selection_spans(&file, pos);
assert!(spans.is_empty());
}
#[test]
fn test_feature_just_after_span() {
let feature = make_feature_with_span("afterFeature", Some(make_span(5, 10, 7, 20)));
let file = KerMLFile {
namespace: None,
elements: vec![Element::Feature(feature)],
};
let pos = Position::new(7, 21); let spans = find_kerml_selection_spans(&file, pos);
assert!(spans.is_empty());
}
#[test]
fn test_multiple_features_select_correct_one() {
let feature1 = make_feature_with_span("feature1", Some(make_span(1, 0, 3, 1)));
let feature2 = make_feature_with_span("feature2", Some(make_span(5, 0, 7, 1)));
let feature3 = make_feature_with_span("feature3", Some(make_span(10, 0, 12, 1)));
let file = KerMLFile {
namespace: None,
elements: vec![
Element::Feature(feature1),
Element::Feature(feature2),
Element::Feature(feature3),
],
};
let pos = Position::new(6, 5); let spans = find_kerml_selection_spans(&file, pos);
assert_eq!(spans.len(), 1);
assert_eq!(spans[0].start.line, 5);
assert_eq!(spans[0].end.line, 7);
}