#![allow(clippy::unwrap_used)]
use crate::semantic::Workspace;
use crate::semantic::processors::{SemanticTokenCollector, TokenType};
use crate::syntax::SyntaxFile;
use crate::syntax::parser::parse_content;
use std::path::PathBuf;
fn create_workspace(source: &str) -> Workspace<SyntaxFile> {
let path = PathBuf::from("test.sysml");
let syntax_file = parse_content(source, &path).expect("Parse should succeed");
let mut workspace = Workspace::<SyntaxFile>::new();
workspace.add_file(path.clone(), syntax_file);
workspace.populate_file(&path).expect("Failed to populate");
workspace
}
fn count_tokens_by_type(workspace: &Workspace<SyntaxFile>, token_type: TokenType) -> usize {
SemanticTokenCollector::collect_from_workspace(workspace, "test.sysml")
.iter()
.filter(|t| t.token_type == token_type)
.count()
}
#[test]
fn test_part_definition_produces_type_token() {
let workspace = create_workspace("part def Vehicle;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_action_definition_produces_type_token() {
let workspace = create_workspace("action def Drive;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_requirement_definition_produces_type_token() {
let workspace = create_workspace("requirement def Safety;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_port_definition_produces_type_token() {
let workspace = create_workspace("port def DataPort;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_item_definition_produces_type_token() {
let workspace = create_workspace("item def Fuel;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_attribute_definition_produces_type_token() {
let workspace = create_workspace("attribute def Speed;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_concern_definition_produces_type_token() {
let workspace = create_workspace("concern def Maintainability;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_case_definition_produces_type_token() {
let workspace = create_workspace("case def TestCase;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_view_definition_produces_type_token() {
let workspace = create_workspace("view def SystemView;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_viewpoint_definition_produces_type_token() {
let workspace = create_workspace("viewpoint def EngineeringView;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_constraint_definition_produces_type_token() {
let workspace = create_workspace("constraint def PowerConstraint;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_calculation_definition_produces_type_token() {
let workspace = create_workspace("calc def ComputeSpeed;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_state_definition_produces_type_token() {
let workspace = create_workspace("state def Running;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_connection_definition_produces_type_token() {
let workspace = create_workspace("connection def DataFlow;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_interface_definition_produces_type_token() {
let workspace = create_workspace("interface def USB;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_allocation_definition_produces_type_token() {
let workspace = create_workspace("allocation def Hardware;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_enumeration_definition_produces_type_token() {
let workspace = create_workspace("enum def Color;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_flow_definition_produces_type_token() {
let workspace = create_workspace("flow def EnergyFlow;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_metadata_definition_produces_type_token() {
let workspace = create_workspace("metadata def CustomMeta;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_part_usage_produces_property_token() {
let workspace = create_workspace("part engine;");
assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 1);
}
#[test]
fn test_attribute_usage_produces_property_token() {
let workspace = create_workspace("attribute mass;");
assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 1);
}
#[test]
fn test_port_usage_produces_property_token() {
let workspace = create_workspace("port dataIn;");
assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 1);
}
#[test]
fn test_action_usage_produces_property_token() {
let workspace = create_workspace("action drive;");
assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 1);
}
#[test]
fn test_item_usage_produces_property_token() {
let workspace = create_workspace("item fuel;");
assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 1);
}
#[test]
fn test_requirement_usage_produces_property_token() {
let workspace = create_workspace("requirement safety;");
assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 1);
}
#[test]
fn test_constraint_usage_produces_property_token() {
let workspace = create_workspace("constraint power;");
assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 1);
}
#[test]
fn test_state_usage_produces_property_token() {
let workspace = create_workspace("state running;");
assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 1);
}
#[test]
fn test_specialization_produces_type_token_for_target() {
let workspace = create_workspace("part def ElectricCar :> Car;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 2);
}
#[test]
fn test_redefinition_produces_type_token_for_target() {
let workspace = create_workspace("part def SportsCar :>> Car;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 2);
}
#[test]
fn test_subsetting_produces_property_token_for_target() {
let workspace = create_workspace("part wheels :> components;");
assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 2);
}
#[test]
fn test_typing_produces_type_token_for_target() {
let workspace = create_workspace("part engine : Engine;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}
#[test]
fn test_multiple_specializations_produce_type_tokens() {
let workspace = create_workspace("part def HybridCar :> Car, Electric;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 3);
}
#[test]
fn test_metadata_body_usage_produces_tokens() {
let workspace = create_workspace(
r#"metadata def TestMeta {
ref :>> annotatedElement : Usage;
}"#,
);
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 2);
}
#[test]
fn test_metadata_body_usage_with_value_produces_tokens() {
let workspace = create_workspace(
r#"metadata def TestMeta {
ref :>> baseType = causes as Usage;
}"#,
);
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 2);
}
#[test]
fn test_anonymous_usage_with_redefinition_gets_property_token() {
let workspace = create_workspace(
r#"metadata def TestMeta {
ref :>> annotatedElement : Usage;
ref :>> baseType = causes as Usage;
}"#,
);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
let type_tokens: Vec<_> = tokens
.iter()
.filter(|t| t.token_type == TokenType::Type)
.collect();
let property_tokens: Vec<_> = tokens
.iter()
.filter(|t| t.token_type == TokenType::Property)
.collect();
assert_eq!(
type_tokens.len(),
3,
"Expected 3 Type tokens (TestMeta, Usage x2), got {}",
type_tokens.len()
);
assert_eq!(
property_tokens.len(),
3,
"Expected 3 Property tokens (annotatedElement, baseType, causes), got {}",
property_tokens.len()
);
assert!(
property_tokens
.iter()
.any(|t| t.line == 1 && t.column == 12),
"annotatedElement should have Property token"
);
assert!(
property_tokens
.iter()
.any(|t| t.line == 2 && t.column == 12),
"baseType should have Property token"
);
}
#[test]
fn test_anonymous_usage_with_subsetting_gets_property_token() {
let workspace = create_workspace(
r#"metadata def TestMeta {
ref :> annotatedElement : ConnectionDefinition;
ref :> baseType : ConnectionUsage;
}"#,
);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
let property_tokens: Vec<_> = tokens
.iter()
.filter(|t| t.token_type == TokenType::Property)
.collect();
assert_eq!(
property_tokens.len(),
2,
"Expected 2 Property tokens (annotatedElement, baseType), got {}",
property_tokens.len()
);
assert!(
property_tokens
.iter()
.any(|t| t.line == 1 && t.column == 11),
"annotatedElement should have Property token"
);
assert!(
property_tokens
.iter()
.any(|t| t.line == 2 && t.column == 11),
"baseType should have Property token"
);
}
#[test]
fn test_metadata_body_qualified_type_reference() {
let workspace = create_workspace(
r#"metadata def CausationMetadata {
ref :> annotatedElement : SysML::ConnectionDefinition;
ref :> annotatedElement : SysML::ConnectionUsage;
}"#,
);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("\n=== Symbol Table ===");
for sym in workspace.symbol_table().iter_symbols() {
println!(
" {} -> {:?} @ {:?}",
sym.qualified_name(),
std::mem::discriminant(sym),
sym.span()
);
}
println!("\n=== Reference Index ===");
for target in workspace.reference_index().targets() {
for ref_info in workspace.reference_index().get_references(target) {
println!(
" {} <- {} @ {:?}",
target, ref_info.source_qname, ref_info.span
);
}
}
println!("\n=== All Semantic Tokens ===");
for t in &tokens {
println!(
"Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
let type_tokens: Vec<_> = tokens
.iter()
.filter(|t| t.token_type == TokenType::Type)
.collect();
let property_tokens: Vec<_> = tokens
.iter()
.filter(|t| t.token_type == TokenType::Property)
.collect();
println!("\n=== Type tokens ({}) ===", type_tokens.len());
for t in &type_tokens {
println!(" Line {}, Col {}, Len {}", t.line, t.column, t.length);
}
println!("\n=== Property tokens ({}) ===", property_tokens.len());
for t in &property_tokens {
println!(" Line {}, Col {}, Len {}", t.line, t.column, t.length);
}
assert!(
type_tokens.len() >= 3,
"Expected at least 3 Type tokens (CausationMetadata, SysML::ConnectionDefinition, SysML::ConnectionUsage), got {}",
type_tokens.len()
);
assert!(
property_tokens.len() >= 2,
"Expected at least 2 Property tokens (annotatedElement x2), got {}",
property_tokens.len()
);
}
#[test]
fn test_metadata_def_with_specialization() {
let workspace = create_workspace("metadata def CustomMeta :> SemanticMetadata;");
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 2);
}
#[test]
fn test_package_produces_namespace_token() {
let workspace = create_workspace("package MyPackage;");
assert!(count_tokens_by_type(&workspace, TokenType::Namespace) >= 1);
}
#[test]
fn test_nested_packages_produce_namespace_tokens() {
let workspace = create_workspace(
r#"package Outer {
package Inner;
}"#,
);
assert!(count_tokens_by_type(&workspace, TokenType::Namespace) >= 2);
}
#[test]
fn test_import_produces_namespace_token() {
let workspace = create_workspace("import ScalarValues::*;");
assert!(count_tokens_by_type(&workspace, TokenType::Namespace) >= 1);
}
#[test]
fn test_member_import_produces_namespace_token() {
let workspace = create_workspace("import ScalarValues::Real;");
assert!(count_tokens_by_type(&workspace, TokenType::Namespace) >= 1);
}
#[test]
fn test_alias_produces_variable_token() {
let workspace = create_workspace("alias Car for Vehicle;");
assert!(count_tokens_by_type(&workspace, TokenType::Variable) >= 1);
}
#[test]
fn test_definition_with_nested_usages() {
let workspace = create_workspace(
r#"part def Vehicle {
attribute mass : Real;
part engine : Engine;
}"#,
);
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 3);
assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 2);
}
#[test]
fn test_package_with_definitions_and_usages() {
let workspace = create_workspace(
r#"package Test {
part def Car;
part myCar : Car;
}"#,
);
assert!(count_tokens_by_type(&workspace, TokenType::Namespace) >= 1);
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 2); assert!(count_tokens_by_type(&workspace, TokenType::Property) >= 1);
}
#[test]
fn test_qualified_type_reference() {
let workspace = create_workspace(r#"part engine : Automotive::Engine;"#);
assert!(count_tokens_by_type(&workspace, TokenType::Type) >= 1);
}