#![allow(clippy::unwrap_used)]
#![allow(clippy::panic)]
use crate::core::{Position, Span};
use crate::semantic::symbol_table::{Symbol, SymbolTable};
use crate::semantic::types::InlayHintKind;
use crate::syntax::sysml::ast::{
Alias, Comment, Definition, DefinitionKind, DefinitionMember, Element, Import, Package,
Relationships, SysMLFile, Usage, UsageKind, UsageMember,
};
use super::super::inlay_hints::extract_inlay_hints;
#[test]
fn test_collect_hints_empty_file() {
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![],
};
let symbol_table = SymbolTable::new();
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_hints_package_traversal() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(3, 4, 3, 9)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let package = Package {
name: Some("MyPackage".to_string()),
elements: vec![Element::Usage(usage)],
span: None,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Package(package)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("Type1"));
}
#[test]
fn test_collect_hints_nested_packages() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(5, 8, 5, 13)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let inner_package = Package {
name: Some("InnerPackage".to_string()),
elements: vec![Element::Usage(usage)],
span: None,
};
let outer_package = Package {
name: Some("OuterPackage".to_string()),
elements: vec![Element::Package(inner_package)],
span: None,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Package(outer_package)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("Type1"));
}
#[test]
fn test_collect_hints_definition_element() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"wheel".to_string(),
Symbol::Usage {
name: "wheel".to_string(),
qualified_name: "wheel".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Wheel".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let nested_usage = Usage {
kind: UsageKind::Part,
name: Some("wheel".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(3, 8, 3, 13)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let definition = Definition {
kind: DefinitionKind::Part,
name: Some("Vehicle".to_string()),
relationships: Relationships::default(),
body: vec![DefinitionMember::Usage(Box::new(nested_usage))],
span: Some(Span::from_coords(1, 0, 4, 1)),
short_name: None,
short_name_span: None,
is_abstract: false,
is_variation: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Definition(definition)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 1);
assert_eq!(hints[0].kind, InlayHintKind::Type);
assert!(hints[0].label.contains("Wheel"));
}
#[test]
fn test_collect_hints_definition_with_multiple_usages() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"engine".to_string(),
Symbol::Usage {
name: "engine".to_string(),
qualified_name: "engine".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Engine".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
symbol_table
.insert(
"transmission".to_string(),
Symbol::Usage {
name: "transmission".to_string(),
qualified_name: "transmission".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Transmission".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage1 = Usage {
kind: UsageKind::Part,
name: Some("engine".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(3, 4, 3, 10)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let usage2 = Usage {
kind: UsageKind::Part,
name: Some("transmission".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(4, 4, 4, 16)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let definition = Definition {
kind: DefinitionKind::Part,
name: Some("Powertrain".to_string()),
relationships: Relationships::default(),
body: vec![
DefinitionMember::Usage(Box::new(usage1)),
DefinitionMember::Usage(Box::new(usage2)),
],
span: Some(Span::from_coords(1, 0, 5, 1)),
short_name: None,
short_name_span: None,
is_abstract: false,
is_variation: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Definition(definition)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 2);
assert!(hints[0].label.contains("Engine"));
assert!(hints[1].label.contains("Transmission"));
}
#[test]
fn test_collect_hints_definition_with_comments_only() {
let symbol_table = SymbolTable::new();
let comment = Comment::new("This is a comment", None);
let definition = Definition {
kind: DefinitionKind::Part,
name: Some("Vehicle".to_string()),
relationships: Relationships::default(),
body: vec![DefinitionMember::Comment(Box::new(comment))],
span: Some(Span::from_coords(1, 0, 3, 1)),
short_name: None,
short_name_span: None,
is_abstract: false,
is_variation: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Definition(definition)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_hints_usage_element() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"myPart".to_string(),
Symbol::Usage {
name: "myPart".to_string(),
qualified_name: "myPart".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Vehicle".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage = Usage {
kind: UsageKind::Part,
name: Some("myPart".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(1, 0, 1, 6)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 1);
assert_eq!(hints[0].kind, InlayHintKind::Type);
assert!(hints[0].label.contains("Vehicle"));
}
#[test]
fn test_collect_hints_comment_element_ignored() {
let symbol_table = SymbolTable::new();
let comment = Comment::new(
"This is a top-level comment",
Some(Span::from_coords(1, 0, 1, 30)),
);
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Comment(comment)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_hints_import_element_ignored() {
let symbol_table = SymbolTable::new();
let import = Import {
path: "SomePackage::*".to_string(),
path_span: None,
is_recursive: false,
is_public: false,
span: Some(Span::from_coords(1, 0, 1, 20)),
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Import(import)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_hints_alias_element_ignored() {
let symbol_table = SymbolTable::new();
let alias = Alias {
name: Some("MyAlias".to_string()),
target: "OriginalName".to_string(),
target_span: None,
span: Some(Span::from_coords(1, 0, 1, 25)),
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Alias(alias)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_hints_mixed_element_types() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let comment = Comment::new("Comment", Some(Span::from_coords(1, 0, 1, 10)));
let import = Import {
path: "Package::*".to_string(),
path_span: None,
is_recursive: false,
is_public: false,
span: Some(Span::from_coords(2, 0, 2, 15)),
};
let usage = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(3, 0, 3, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let alias = Alias {
name: Some("A".to_string()),
target: "B".to_string(),
target_span: None,
span: Some(Span::from_coords(4, 0, 4, 10)),
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![
Element::Comment(comment),
Element::Import(import),
Element::Usage(usage),
Element::Alias(alias),
],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("Type1"));
}
#[test]
fn test_collect_hints_deeply_nested_usages() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"sensor".to_string(),
Symbol::Usage {
name: "sensor".to_string(),
qualified_name: "sensor".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Sensor".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let deep_usage = Usage {
kind: UsageKind::Part,
name: Some("sensor".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(5, 12, 5, 18)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let mid_usage = Usage {
kind: UsageKind::Part,
name: Some("controller".to_string()),
relationships: Relationships::default(),
body: vec![UsageMember::Usage(Box::new(deep_usage))],
span: Some(Span::from_coords(3, 8, 6, 9)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let top_usage = Usage {
kind: UsageKind::Part,
name: Some("system".to_string()),
relationships: Relationships::default(),
body: vec![UsageMember::Usage(Box::new(mid_usage))],
span: Some(Span::from_coords(1, 4, 7, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(top_usage)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("Sensor"));
}
#[test]
fn test_collect_hints_usage_with_comment_members() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"innerPart".to_string(),
Symbol::Usage {
name: "innerPart".to_string(),
qualified_name: "innerPart".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("InnerType".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let comment = Comment::new("Inner comment", None);
let inner_usage = Usage {
kind: UsageKind::Part,
name: Some("innerPart".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(3, 4, 3, 13)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let outer_usage = Usage {
kind: UsageKind::Part,
name: Some("outerPart".to_string()),
relationships: Relationships::default(),
body: vec![
UsageMember::Comment(comment),
UsageMember::Usage(Box::new(inner_usage)),
],
span: Some(Span::from_coords(1, 0, 4, 1)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(outer_usage)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("InnerType"));
}
#[test]
fn test_collect_hints_package_definition_usage_hierarchy() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"component".to_string(),
Symbol::Usage {
name: "component".to_string(),
qualified_name: "component".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Component".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage = Usage {
kind: UsageKind::Part,
name: Some("component".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(4, 8, 4, 17)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let definition = Definition {
kind: DefinitionKind::Part,
name: Some("System".to_string()),
relationships: Relationships::default(),
body: vec![DefinitionMember::Usage(Box::new(usage))],
span: Some(Span::from_coords(2, 4, 5, 5)),
short_name: None,
short_name_span: None,
is_abstract: false,
is_variation: false,
};
let package = Package {
name: Some("RootPackage".to_string()),
elements: vec![Element::Definition(definition)],
span: None,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Package(package)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("Component"));
}
#[test]
fn test_collect_hints_range_filter_excludes_before() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(2, 0, 2, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage)],
};
let range = (
Position { line: 5, column: 0 },
Position {
line: 10,
column: 0,
},
);
let hints = extract_inlay_hints(&file, &symbol_table, Some(range));
assert!(hints.is_empty());
}
#[test]
fn test_collect_hints_range_filter_excludes_after() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(10, 0, 10, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage)],
};
let range = (
Position { line: 1, column: 0 },
Position { line: 5, column: 0 },
);
let hints = extract_inlay_hints(&file, &symbol_table, Some(range));
assert!(hints.is_empty());
}
#[test]
fn test_collect_hints_range_filter_includes_in_range() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(5, 0, 5, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage)],
};
let range = (
Position { line: 1, column: 0 },
Position {
line: 10,
column: 0,
},
);
let hints = extract_inlay_hints(&file, &symbol_table, Some(range));
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("Type1"));
}
#[test]
fn test_collect_hints_range_filter_nested_usages() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"inner1".to_string(),
Symbol::Usage {
name: "inner1".to_string(),
qualified_name: "inner1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
symbol_table
.insert(
"inner2".to_string(),
Symbol::Usage {
name: "inner2".to_string(),
qualified_name: "inner2".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type2".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let inner1 = Usage {
kind: UsageKind::Part,
name: Some("inner1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(3, 4, 3, 10)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let inner2 = Usage {
kind: UsageKind::Part,
name: Some("inner2".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(15, 4, 15, 10)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let outer = Usage {
kind: UsageKind::Part,
name: Some("outer".to_string()),
relationships: Relationships::default(),
body: vec![
UsageMember::Usage(Box::new(inner1)),
UsageMember::Usage(Box::new(inner2)),
],
span: Some(Span::from_coords(1, 0, 20, 0)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(outer)],
};
let range = (
Position { line: 1, column: 0 },
Position {
line: 10,
column: 50,
},
);
let hints = extract_inlay_hints(&file, &symbol_table, Some(range));
assert_eq!(hints.len(), 0);
}
#[test]
fn test_collect_hints_range_filter_boundary_start() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(5, 0, 5, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage)],
};
let range = (
Position { line: 5, column: 0 },
Position {
line: 10,
column: 0,
},
);
let hints = extract_inlay_hints(&file, &symbol_table, Some(range));
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("Type1"));
}
#[test]
fn test_collect_hints_range_filter_boundary_end() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(10, 0, 10, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage)],
};
let range = (
Position { line: 5, column: 0 },
Position {
line: 10,
column: 10,
},
);
let hints = extract_inlay_hints(&file, &symbol_table, Some(range));
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("Type1"));
}
#[test]
fn test_collect_hints_multiple_packages_with_same_usage_names() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part".to_string(),
Symbol::Usage {
name: "part".to_string(),
qualified_name: "part".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage1 = Usage {
kind: UsageKind::Part,
name: Some("part".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(3, 4, 3, 8)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let usage2 = Usage {
kind: UsageKind::Part,
name: Some("part".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(7, 4, 7, 8)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let package1 = Package {
name: Some("Package1".to_string()),
elements: vec![Element::Usage(usage1)],
span: None,
};
let package2 = Package {
name: Some("Package2".to_string()),
elements: vec![Element::Usage(usage2)],
span: None,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Package(package1), Element::Package(package2)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 2);
assert!(hints[0].label.contains("Type1"));
assert!(hints[1].label.contains("Type1"));
}
#[test]
fn test_collect_hints_empty_package() {
let symbol_table = SymbolTable::new();
let package = Package {
name: Some("EmptyPackage".to_string()),
elements: vec![],
span: None,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Package(package)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_hints_empty_definition() {
let symbol_table = SymbolTable::new();
let definition = Definition {
kind: DefinitionKind::Part,
name: Some("EmptyDef".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(1, 0, 2, 1)),
short_name: None,
short_name_span: None,
is_abstract: false,
is_variation: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Definition(definition)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_hints_usage_without_span() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: None, short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_hints_multiple_element_types_in_package() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let comment = Comment::new("Comment", None);
let import = Import {
path: "SomePackage::*".to_string(),
path_span: None,
is_recursive: false,
is_public: false,
span: None,
};
let usage = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(5, 4, 5, 9)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let definition = Definition {
kind: DefinitionKind::Part,
name: Some("Def1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(7, 4, 8, 5)),
short_name: None,
short_name_span: None,
is_abstract: false,
is_variation: false,
};
let package = Package {
name: Some("MixedPackage".to_string()),
elements: vec![
Element::Comment(comment),
Element::Import(import),
Element::Usage(usage),
Element::Definition(definition),
],
span: None,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Package(package)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("Type1"));
}
#[test]
fn test_collect_hints_no_range_filter() {
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"part1".to_string(),
Symbol::Usage {
name: "part1".to_string(),
qualified_name: "part1".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type1".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
symbol_table
.insert(
"part2".to_string(),
Symbol::Usage {
name: "part2".to_string(),
qualified_name: "part2".to_string(),
scope_id: 0,
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Type2".to_string()),
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage1 = Usage {
kind: UsageKind::Part,
name: Some("part1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(1, 0, 1, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let usage2 = Usage {
kind: UsageKind::Part,
name: Some("part2".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(100, 0, 100, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage1), Element::Usage(usage2)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 2);
assert!(hints[0].label.contains("Type1"));
assert!(hints[1].label.contains("Type2"));
}
#[test]
fn test_collect_usage_hints_with_explicit_type() {
use super::super::inlay_hints::extract_inlay_hints;
let symbol_table = SymbolTable::new();
let usage = Usage {
kind: UsageKind::Part,
name: Some("myCar".to_string()),
relationships: Relationships {
typed_by: Some("Vehicle".to_string()),
..Default::default()
},
body: vec![],
span: Some(Span::from_coords(3, 4, 3, 9)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_usage_hints_nested_usage() {
use super::super::inlay_hints::extract_inlay_hints;
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"engine".to_string(),
Symbol::Usage {
name: "engine".to_string(),
qualified_name: "engine".to_string(),
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Engine".to_string()),
scope_id: 0,
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let nested_usage = Usage {
kind: UsageKind::Part,
name: Some("engine".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(4, 8, 4, 14)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let parent_usage = Usage {
kind: UsageKind::Part,
name: Some("vehicle".to_string()),
relationships: Relationships::default(),
body: vec![UsageMember::Usage(Box::new(nested_usage))],
span: Some(Span::from_coords(3, 4, 5, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(parent_usage)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert_eq!(hints.len(), 1);
assert!(hints[0].label.contains("Engine"));
assert_eq!(hints[0].position.line, 4);
}
#[test]
fn test_collect_usage_hints_with_range_filter() {
use super::super::inlay_hints::extract_inlay_hints;
use crate::core::Position;
let mut symbol_table = SymbolTable::new();
symbol_table
.insert(
"car1".to_string(),
Symbol::Usage {
name: "car1".to_string(),
qualified_name: "car1".to_string(),
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Vehicle".to_string()),
scope_id: 0,
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
symbol_table
.insert(
"car2".to_string(),
Symbol::Usage {
name: "car2".to_string(),
qualified_name: "car2".to_string(),
kind: "Part".to_string(),
semantic_role: None,
usage_type: Some("Vehicle".to_string()),
scope_id: 0,
source_file: None,
span: None,
documentation: None,
subsets: Vec::new(),
redefines: Vec::new(),
performs: Vec::new(),
references: Vec::new(),
},
)
.unwrap();
let usage1 = Usage {
kind: UsageKind::Part,
name: Some("car1".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(3, 4, 3, 8)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let usage2 = Usage {
kind: UsageKind::Part,
name: Some("car2".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(5, 4, 5, 8)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage1), Element::Usage(usage2)],
};
let range = Some((
Position { line: 3, column: 0 },
Position {
line: 3,
column: 100,
},
));
let hints = extract_inlay_hints(&file, &symbol_table, range);
for hint in hints {
assert_eq!(hint.position.line, 3);
}
}
#[test]
fn test_collect_usage_hints_empty_file() {
use super::super::inlay_hints::extract_inlay_hints;
let symbol_table = SymbolTable::new();
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_usage_hints_usage_without_name() {
use super::super::inlay_hints::extract_inlay_hints;
let symbol_table = SymbolTable::new();
let usage = Usage {
kind: UsageKind::Part,
name: None, relationships: Relationships {
typed_by: Some("Engine".to_string()),
..Default::default()
},
body: vec![],
span: Some(Span::from_coords(3, 8, 3, 15)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(usage)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}
#[test]
fn test_collect_usage_hints_deeply_nested() {
use super::super::inlay_hints::extract_inlay_hints;
let symbol_table = SymbolTable::new();
let level4 = Usage {
kind: UsageKind::Part,
name: Some("level4".to_string()),
relationships: Relationships::default(),
body: vec![],
span: Some(Span::from_coords(7, 16, 7, 22)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let level3 = Usage {
kind: UsageKind::Part,
name: Some("level3".to_string()),
relationships: Relationships::default(),
body: vec![UsageMember::Usage(Box::new(level4))],
span: Some(Span::from_coords(6, 12, 8, 13)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let level2 = Usage {
kind: UsageKind::Part,
name: Some("level2".to_string()),
relationships: Relationships::default(),
body: vec![UsageMember::Usage(Box::new(level3))],
span: Some(Span::from_coords(5, 8, 9, 9)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let level1 = Usage {
kind: UsageKind::Part,
name: Some("level1".to_string()),
relationships: Relationships::default(),
body: vec![UsageMember::Usage(Box::new(level2))],
span: Some(Span::from_coords(3, 4, 10, 5)),
short_name: None,
short_name_span: None,
expression_refs: Vec::new(),
is_derived: false,
is_const: false,
};
let file = SysMLFile {
namespace: None,
namespaces: vec![],
elements: vec![Element::Usage(level1)],
};
let hints = extract_inlay_hints(&file, &symbol_table, None);
assert!(hints.is_empty());
}