#![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 find_token_at(
tokens: &[crate::semantic::processors::SemanticToken],
line: u32,
col: u32,
) -> Option<&crate::semantic::processors::SemanticToken> {
tokens.iter().find(|t| t.line == line && t.column == col)
}
fn assert_token_at(
tokens: &[crate::semantic::processors::SemanticToken],
line: u32,
col: u32,
expected_type: TokenType,
description: &str,
) {
let token = find_token_at(tokens, line, col);
assert!(
token.is_some(),
"Expected token at line {}, col {} for '{}'. Available tokens: {:?}",
line,
col,
description,
tokens
);
let token = token.unwrap();
assert_eq!(
token.token_type, expected_type,
"Token at line {}, col {} for '{}' should be {:?}, got {:?}",
line, col, description, expected_type, token.token_type
);
}
#[test]
fn test_named_usage_with_typing() {
let source = "part engine : Engine;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 5, TokenType::Property, "engine (usage name)");
assert_token_at(&tokens, 0, 14, TokenType::Type, "Engine (typing target)");
}
#[test]
fn test_named_attribute_with_typing() {
let source = "attribute mass : Real;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 10, TokenType::Property, "mass (usage name)");
assert_token_at(&tokens, 0, 17, TokenType::Type, "Real (typing target)");
}
#[test]
fn test_named_port_with_typing() {
let source = "port dataIn : DataPort;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 5, TokenType::Property, "dataIn (usage name)");
assert_token_at(&tokens, 0, 14, TokenType::Type, "DataPort (typing target)");
}
#[test]
fn test_anonymous_usage_subsetting_only() {
let source = "ref :> annotatedElement;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(
&tokens,
0,
7,
TokenType::Property,
"annotatedElement (subsetting target)",
);
}
#[test]
fn test_anonymous_part_subsetting_only() {
let source = "part :> wheels;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(
&tokens,
0,
8,
TokenType::Property,
"wheels (subsetting target)",
);
}
#[test]
fn test_anonymous_usage_redefinition_only() {
let source = "ref :>> baseType;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(
&tokens,
0,
8,
TokenType::Property,
"baseType (redefinition target)",
);
}
#[test]
fn test_anonymous_attribute_redefinition_only() {
let source = "attribute :>> speed;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(
&tokens,
0,
14,
TokenType::Property,
"speed (redefinition target)",
);
}
#[test]
fn test_anonymous_usage_subsetting_with_typing() {
let source = "ref :> annotatedElement : ConnectionDef;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(
&tokens,
0,
7,
TokenType::Property,
"annotatedElement (subsetting target)",
);
assert_token_at(
&tokens,
0,
26,
TokenType::Type,
"ConnectionDef (typing target)",
);
}
#[test]
fn test_anonymous_usage_redefinition_with_typing() {
let source = "ref :>> baseType : Usage;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(
&tokens,
0,
8,
TokenType::Property,
"baseType (redefinition target)",
);
assert_token_at(&tokens, 0, 19, TokenType::Type, "Usage (typing target)");
}
#[test]
fn test_anonymous_usage_with_qualified_type() {
let source = "ref :> x : SysML::ConnectionDefinition;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 7, TokenType::Property, "x (subsetting target)");
assert_token_at(
&tokens,
0,
11,
TokenType::Type,
"SysML::ConnectionDefinition (qualified type)",
);
}
#[test]
fn test_anonymous_usage_with_long_qualified_type() {
let source = "ref :> elem : A::B::C::D;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(
&tokens,
0,
7,
TokenType::Property,
"elem (subsetting target)",
);
assert_token_at(
&tokens,
0,
14,
TokenType::Type,
"A::B::C::D (qualified type)",
);
}
#[test]
fn test_duplicate_anonymous_usages_subsetting() {
let source = r#"metadata def TestMeta {
ref :> annotatedElement : Type1;
ref :> annotatedElement : Type2;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 13, TokenType::Type, "TestMeta (definition)");
assert_token_at(
&tokens,
1,
11,
TokenType::Property,
"annotatedElement (first, subsetting)",
);
assert_token_at(&tokens, 1, 30, TokenType::Type, "Type1 (first typing)");
assert_token_at(
&tokens,
2,
11,
TokenType::Property,
"annotatedElement (second, subsetting)",
);
assert_token_at(&tokens, 2, 30, TokenType::Type, "Type2 (second typing)");
}
#[test]
fn test_duplicate_anonymous_usages_redefinition() {
let source = r#"metadata def TestMeta {
ref :>> baseType : Usage1;
ref :>> baseType : Usage2;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 13, TokenType::Type, "TestMeta (definition)");
assert_token_at(
&tokens,
1,
12,
TokenType::Property,
"baseType (first, redefinition)",
);
assert_token_at(&tokens, 1, 23, TokenType::Type, "Usage1 (first typing)");
assert_token_at(
&tokens,
2,
12,
TokenType::Property,
"baseType (second, redefinition)",
);
assert_token_at(&tokens, 2, 23, TokenType::Type, "Usage2 (second typing)");
}
#[test]
fn test_anonymous_usage_with_value_and_meta() {
let source = "ref :>> baseType = derivations meta SysML::Usage;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(
&tokens,
0,
8,
TokenType::Property,
"baseType (redefinition target)",
);
}
#[test]
fn test_definition_with_specialization() {
let source = "part def Car :> Vehicle;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 9, TokenType::Type, "Car (definition)");
assert_token_at(
&tokens,
0,
16,
TokenType::Type,
"Vehicle (specialization target)",
);
}
#[test]
fn test_definition_with_multiple_specializations() {
let source = "part def HybridCar :> Car, Electric;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 9, TokenType::Type, "HybridCar (definition)");
assert_token_at(&tokens, 0, 22, TokenType::Type, "Car (specialization)");
assert_token_at(&tokens, 0, 27, TokenType::Type, "Electric (specialization)");
}
#[test]
fn test_definition_with_redefinition() {
let source = "part def SportsCar :>> Car;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 9, TokenType::Type, "SportsCar (definition)");
assert_token_at(&tokens, 0, 23, TokenType::Type, "Car (redefinition target)");
}
#[test]
fn test_usage_with_subsetting_and_typing() {
let source = "part wheels :> components : Wheel;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 5, TokenType::Property, "wheels (usage name)");
assert_token_at(
&tokens,
0,
15,
TokenType::Property,
"components (subsetting target)",
);
assert_token_at(&tokens, 0, 28, TokenType::Type, "Wheel (typing target)");
}
#[test]
fn test_nested_usages_in_definition() {
let source = r#"part def Vehicle {
attribute mass : Real;
part engine : Engine;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 9, TokenType::Type, "Vehicle (definition)");
assert_token_at(
&tokens,
1,
14,
TokenType::Property,
"mass (attribute usage)",
);
assert_token_at(&tokens, 1, 21, TokenType::Type, "Real (typing)");
assert_token_at(&tokens, 2, 9, TokenType::Property, "engine (part usage)");
assert_token_at(&tokens, 2, 18, TokenType::Type, "Engine (typing)");
}
#[test]
fn test_deeply_nested_usages() {
let source = r#"part def Car {
part engine {
attribute power : Real;
}
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 9, TokenType::Type, "Car (definition)");
assert_token_at(&tokens, 1, 9, TokenType::Property, "engine (part usage)");
assert_token_at(&tokens, 2, 18, TokenType::Property, "power (attribute)");
assert_token_at(&tokens, 2, 26, TokenType::Type, "Real (typing)");
}
#[test]
fn test_definition_with_short_name() {
let source = "part def <eng> Engine;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 15, TokenType::Type, "Engine (definition)");
let short_token = find_token_at(&tokens, 0, 10);
if let Some(t) = short_token {
println!("Short name token: {:?}", t);
assert!(
t.token_type == TokenType::Variable || t.token_type == TokenType::Type,
"Short name should be Variable or Type, got {:?}",
t.token_type
);
}
}
#[test]
fn test_metadata_def_with_short_name() {
let source = "metadata def <orig> OriginalMetadata :> SemanticMetadata;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(
&tokens,
0,
20,
TokenType::Type,
"OriginalMetadata (definition)",
);
assert_token_at(
&tokens,
0,
40,
TokenType::Type,
"SemanticMetadata (specialization)",
);
}
#[test]
fn test_package_token() {
let source = "package MyPackage;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 8, TokenType::Namespace, "MyPackage (package)");
}
#[test]
fn test_import_token() {
let source = r#"package Test {
import SysML::*;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 8, TokenType::Namespace, "Test (package)");
let import_token = find_token_at(&tokens, 1, 11);
if let Some(t) = import_token {
assert_eq!(
t.token_type,
TokenType::Namespace,
"Import path should be Namespace"
);
}
}
#[test]
fn test_action_usage_with_typing() {
let source = "action move : Move;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 7, TokenType::Property, "move (action usage)");
assert_token_at(&tokens, 0, 14, TokenType::Type, "Move (typing)");
}
#[test]
fn test_requirement_def() {
let source = "requirement def SafetyReq;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 16, TokenType::Type, "SafetyReq (definition)");
}
#[test]
fn test_state_def() {
let source = "state def EngineState;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 10, TokenType::Type, "EngineState (definition)");
}
#[test]
fn test_connection_def() {
let source = "connection def Link;";
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("Tokens: {:?}", tokens);
assert_token_at(&tokens, 0, 15, TokenType::Type, "Link (definition)");
}
#[test]
fn test_causation_metadata_pattern() {
let source = r#"metadata def CausationMetadata {
:> annotatedElement : SysML::ConnectionDefinition;
:> annotatedElement : SysML::ConnectionUsage;
:>> baseType = derivations meta SysML::Usage;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== All tokens ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(
&tokens,
0,
13,
TokenType::Type,
"CausationMetadata (definition)",
);
}
#[test]
fn test_ref_usage_pattern_in_metadata() {
let source = r#"metadata def TestMeta {
ref :> annotatedElement : SysML::Usage;
ref :>> baseType : Type;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== All tokens ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 13, TokenType::Type, "TestMeta (definition)");
assert_token_at(
&tokens,
1,
11,
TokenType::Property,
"annotatedElement (subsetting)",
);
assert_token_at(&tokens, 1, 30, TokenType::Type, "SysML::Usage (typing)");
assert_token_at(
&tokens,
2,
12,
TokenType::Property,
"baseType (redefinition)",
);
assert_token_at(&tokens, 2, 23, TokenType::Type, "Type (typing)");
}
#[test]
fn test_reference_binding_operator() {
let source = r#"part def System;
requirement def Req1;
connection def Derivation {
end r1 : Req1;
end r2 : Req1;
}
part system : System {
requirement req1 : Req1;
requirement req2 : Req1;
connection deriv : Derivation {
end r1 ::> req1;
end r2 ::> req2;
}
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== All tokens ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 13, 12, TokenType::Property, "r1 (end usage name)");
assert_token_at(
&tokens,
13,
19,
TokenType::Property,
"req1 (reference binding target)",
);
assert_token_at(&tokens, 14, 12, TokenType::Property, "r2 (end usage name)");
assert_token_at(
&tokens,
14,
19,
TokenType::Property,
"req2 (reference binding target)",
);
}
#[test]
fn test_reference_binding_in_anonymous_connection() {
let source = r#"requirement def Req1;
requirement def Req1_1;
part def Context {
requirement req1 : Req1;
requirement req1_1 : Req1_1;
}
part context : Context;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== All tokens ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 16, TokenType::Type, "Req1");
assert_token_at(&tokens, 1, 16, TokenType::Type, "Req1_1");
assert_token_at(&tokens, 3, 9, TokenType::Type, "Context");
assert_token_at(&tokens, 4, 16, TokenType::Property, "req1");
assert_token_at(&tokens, 4, 23, TokenType::Type, "Req1");
assert_token_at(&tokens, 5, 16, TokenType::Property, "req1_1");
assert_token_at(&tokens, 5, 25, TokenType::Type, "Req1_1");
assert_token_at(&tokens, 8, 5, TokenType::Property, "context");
assert_token_at(&tokens, 8, 15, TokenType::Type, "Context");
}
fn create_multi_file_workspace(files: &[(&str, &str)]) -> Workspace<SyntaxFile> {
let mut workspace = Workspace::<SyntaxFile>::new();
for (filename, source) in files {
let path = PathBuf::from(*filename);
let syntax_file = parse_content(source, &path).expect("Parse should succeed");
workspace.add_file(path, syntax_file);
}
for (filename, _) in files {
let path = PathBuf::from(*filename);
workspace.populate_file(&path).expect("Failed to populate");
}
workspace
}
#[test]
fn test_cross_file_typing_reference() {
let files = &[
(
"types.sysml",
r#"package Types {
part def Engine;
part def Wheel;
}"#,
),
(
"vehicle.sysml",
r#"package Vehicle {
import Types::*;
part engine : Engine;
part wheels : Wheel;
}"#,
),
];
let workspace = create_multi_file_workspace(files);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "vehicle.sysml");
println!("=== Cross-file tokens ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 3, 9, TokenType::Property, "engine (usage)");
assert_token_at(&tokens, 3, 18, TokenType::Type, "Engine (cross-file type)");
assert_token_at(&tokens, 4, 9, TokenType::Property, "wheels (usage)");
assert_token_at(&tokens, 4, 18, TokenType::Type, "Wheel (cross-file type)");
}
#[test]
fn test_cross_file_subsetting_reference() {
let files = &[
(
"base.sysml",
r#"package Base {
part def Vehicle {
part component;
}
}"#,
),
(
"car.sysml",
r#"package Car {
import Base::*;
part def Car :> Vehicle {
part engine :> component;
}
}"#,
),
];
let workspace = create_multi_file_workspace(files);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "car.sysml");
println!("=== Cross-file subsetting tokens ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 3, 13, TokenType::Type, "Car (definition)");
assert_token_at(
&tokens,
3,
20,
TokenType::Type,
"Vehicle (cross-file specialization)",
);
assert_token_at(&tokens, 4, 13, TokenType::Property, "engine (usage)");
assert_token_at(
&tokens,
4,
23,
TokenType::Property,
"component (cross-file subsetting)",
);
}
#[test]
fn test_cross_file_qualified_reference() {
let files = &[
(
"stdlib.sysml",
r#"package SysML {
part def Usage;
part def ConnectionDefinition;
}"#,
),
(
"metadata.sysml",
r#"metadata def TestMeta {
ref :> annotatedElement : SysML::Usage;
ref :>> baseType : SysML::ConnectionDefinition;
}"#,
),
];
let workspace = create_multi_file_workspace(files);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "metadata.sysml");
println!("=== Qualified reference tokens ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 13, TokenType::Type, "TestMeta (definition)");
assert_token_at(
&tokens,
1,
11,
TokenType::Property,
"annotatedElement (subsetting)",
);
}
#[test]
fn test_cross_file_import_visibility() {
let files = &[
(
"definitions.sysml",
r#"package Definitions {
part def Motor;
port def PowerPort;
action def Start;
}"#,
),
(
"system.sysml",
r#"package System {
import Definitions::*;
part motor : Motor;
port power : PowerPort;
action start : Start;
}"#,
),
];
let workspace = create_multi_file_workspace(files);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "system.sysml");
println!("=== Import visibility tokens ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 3, 9, TokenType::Property, "motor (usage)");
assert_token_at(&tokens, 3, 17, TokenType::Type, "Motor (imported type)");
assert_token_at(&tokens, 4, 9, TokenType::Property, "power (usage)");
assert_token_at(&tokens, 4, 17, TokenType::Type, "PowerPort (imported type)");
assert_token_at(&tokens, 5, 11, TokenType::Property, "start (usage)");
assert_token_at(&tokens, 5, 19, TokenType::Type, "Start (imported type)");
}
#[test]
fn test_multiple_definitions_same_file() {
let source = r#"part def Vehicle;
part def Engine;
part def Wheel;
port def FuelPort;
action def Accelerate;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Multiple definitions ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 9, TokenType::Type, "Vehicle");
assert_token_at(&tokens, 1, 9, TokenType::Type, "Engine");
assert_token_at(&tokens, 2, 9, TokenType::Type, "Wheel");
assert_token_at(&tokens, 3, 9, TokenType::Type, "FuelPort");
assert_token_at(&tokens, 4, 11, TokenType::Type, "Accelerate");
}
#[test]
fn test_multiple_usages_same_file() {
let source = r#"part def Vehicle;
part def Engine;
part vehicle : Vehicle {
part engine : Engine;
part wheels : Wheel;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Multiple usages ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 3, 5, TokenType::Property, "vehicle (usage)");
assert_token_at(&tokens, 3, 15, TokenType::Type, "Vehicle (type)");
assert_token_at(&tokens, 4, 9, TokenType::Property, "engine (nested usage)");
assert_token_at(&tokens, 4, 18, TokenType::Type, "Engine (type)");
}
#[test]
fn test_chained_specializations() {
let source = r#"part def Base;
part def Middle :> Base;
part def Derived :> Middle;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Chained specializations ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 9, TokenType::Type, "Base");
assert_token_at(&tokens, 1, 9, TokenType::Type, "Middle");
assert_token_at(&tokens, 1, 19, TokenType::Type, "Base (specialization)");
assert_token_at(&tokens, 2, 9, TokenType::Type, "Derived");
assert_token_at(&tokens, 2, 20, TokenType::Type, "Middle (specialization)");
}
#[test]
fn test_multiple_specialization_targets() {
let source = r#"part def A;
part def B;
part def C :> A, B;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Multiple specialization targets ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 2, 9, TokenType::Type, "C");
assert_token_at(&tokens, 2, 14, TokenType::Type, "A (first specialization)");
assert_token_at(&tokens, 2, 17, TokenType::Type, "B (second specialization)");
}
#[test]
fn test_mixed_relationships() {
let source = r#"part def Base {
part component;
}
part def Derived :> Base {
part engine :> component : Engine;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Mixed relationships ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 5, 9, TokenType::Property, "engine (usage)");
assert_token_at(
&tokens,
5,
19,
TokenType::Property,
"component (subsetting)",
);
assert_token_at(&tokens, 5, 31, TokenType::Type, "Engine (typing)");
}
#[test]
fn test_redefinition_on_usage() {
let source = r#"part def Vehicle {
part engine;
}
part myVehicle : Vehicle {
part :>> engine : SpecialEngine;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Redefinition on usage ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(
&tokens,
5,
13,
TokenType::Property,
"engine (redefinition target)",
);
assert_token_at(&tokens, 5, 22, TokenType::Type, "SpecialEngine (typing)");
}
#[test]
fn test_requirement_satisfaction() {
let source = r#"requirement def SafetyReq;
part def BrakingSystem;
part brakes : BrakingSystem;
satisfy requirement safety : SafetyReq by brakes;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Requirement satisfaction ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 16, TokenType::Type, "SafetyReq");
assert_token_at(&tokens, 3, 5, TokenType::Property, "brakes");
assert_token_at(&tokens, 3, 14, TokenType::Type, "BrakingSystem");
assert_token_at(&tokens, 4, 20, TokenType::Property, "safety");
assert_token_at(&tokens, 4, 29, TokenType::Type, "SafetyReq");
}
#[test]
fn test_nested_packages() {
let source = r#"package Outer {
package Inner {
part def Component;
}
part comp : Inner::Component;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Nested packages ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 8, TokenType::Namespace, "Outer");
assert_token_at(&tokens, 1, 12, TokenType::Namespace, "Inner");
assert_token_at(&tokens, 2, 17, TokenType::Type, "Component");
}
#[test]
fn test_action_with_parameters() {
let source = r#"action def Compute;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Action with parameters ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 11, TokenType::Type, "Compute");
}
#[test]
fn test_port_definition_with_attributes() {
let source = r#"port def DataPort {
attribute value : Integer;
attribute status : Boolean;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Port definition with attributes ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 9, TokenType::Type, "DataPort");
assert_token_at(&tokens, 1, 14, TokenType::Property, "value");
assert_token_at(&tokens, 1, 22, TokenType::Type, "Integer");
assert_token_at(&tokens, 2, 14, TokenType::Property, "status");
assert_token_at(&tokens, 2, 23, TokenType::Type, "Boolean");
}
#[test]
fn test_interface_with_ports() {
let source = r#"port def PowerPort;
port def DataPort;
interface def SystemInterface;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Interface with ports ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 9, TokenType::Type, "PowerPort");
assert_token_at(&tokens, 1, 9, TokenType::Type, "DataPort");
assert_token_at(&tokens, 3, 14, TokenType::Type, "SystemInterface");
}
#[test]
fn test_allocation_usage() {
let source = r#"allocation def SoftwareToHardware;
allocation sw2hw : SoftwareToHardware;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Allocation usage ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 15, TokenType::Type, "SoftwareToHardware");
assert_token_at(&tokens, 1, 11, TokenType::Property, "sw2hw");
assert_token_at(&tokens, 1, 19, TokenType::Type, "SoftwareToHardware");
}
#[test]
fn test_state_machine() {
let source = r#"state def EngineState {
state off;
state running;
state stalled;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== State machine ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 10, TokenType::Type, "EngineState");
assert_token_at(&tokens, 1, 10, TokenType::Property, "off");
assert_token_at(&tokens, 2, 10, TokenType::Property, "running");
assert_token_at(&tokens, 3, 10, TokenType::Property, "stalled");
}
#[test]
fn test_enumeration() {
let source = r#"enum def Color {
enum red;
enum green;
enum blue;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Enumeration ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 9, TokenType::Type, "Color");
}
#[test]
fn test_constraint_usage() {
let source = r#"constraint def SpeedLimit {
attribute maxSpeed : Real;
}
constraint speedCheck : SpeedLimit;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Constraint usage ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 15, TokenType::Type, "SpeedLimit");
assert_token_at(&tokens, 4, 11, TokenType::Property, "speedCheck");
assert_token_at(&tokens, 4, 24, TokenType::Type, "SpeedLimit");
}
#[test]
fn test_calculation_usage() {
let source = r#"calc def TotalMass {
in part parts : Part[*];
return : Real;
}
calc totalMass : TotalMass;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Calculation usage ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 9, TokenType::Type, "TotalMass");
assert_token_at(&tokens, 5, 5, TokenType::Property, "totalMass");
assert_token_at(&tokens, 5, 17, TokenType::Type, "TotalMass");
}
#[test]
fn test_view_and_viewpoint() {
let source = r#"viewpoint def SystemOverview;
view systemView : SystemOverview;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== View and viewpoint ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 14, TokenType::Type, "SystemOverview");
assert_token_at(&tokens, 1, 5, TokenType::Property, "systemView");
assert_token_at(&tokens, 1, 18, TokenType::Type, "SystemOverview");
}
#[test]
fn test_deeply_nested_usages_four_levels() {
let source = r#"part def System {
part subsystem {
part component {
part element;
}
}
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Deeply nested usages ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 9, TokenType::Type, "System");
assert_token_at(&tokens, 1, 9, TokenType::Property, "subsystem");
assert_token_at(&tokens, 2, 13, TokenType::Property, "component");
assert_token_at(&tokens, 3, 17, TokenType::Property, "element");
}
#[test]
fn test_anonymous_subsetting_chain() {
let source = r#"part def Base {
part x;
}
part def Derived :> Base {
part :> x {
part nested;
}
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Anonymous subsetting chain ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 5, 12, TokenType::Property, "x (subsetting target)");
assert_token_at(&tokens, 6, 13, TokenType::Property, "nested");
}
#[test]
fn test_multiple_anonymous_usages() {
let source = r#"metadata def Meta {
ref :> annotatedElement : Type1;
ref :> annotatedElement : Type2;
ref :>> baseType : Type3;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Multiple anonymous usages ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 13, TokenType::Type, "Meta");
assert_token_at(
&tokens,
1,
11,
TokenType::Property,
"annotatedElement (first)",
);
assert_token_at(&tokens, 1, 30, TokenType::Type, "Type1");
assert_token_at(
&tokens,
2,
11,
TokenType::Property,
"annotatedElement (second)",
);
assert_token_at(&tokens, 2, 30, TokenType::Type, "Type2");
assert_token_at(&tokens, 3, 12, TokenType::Property, "baseType");
assert_token_at(&tokens, 3, 23, TokenType::Type, "Type3");
}
#[test]
fn test_item_flow() {
let source = r#"part def Source {
out port outPort;
}
part def Sink {
in port inPort;
}
part system {
part source : Source;
part sink : Sink;
flow from source.outPort to sink.inPort;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Item flow ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 9, TokenType::Type, "Source");
assert_token_at(&tokens, 4, 9, TokenType::Type, "Sink");
assert_token_at(&tokens, 9, 9, TokenType::Property, "source");
assert_token_at(&tokens, 9, 18, TokenType::Type, "Source");
assert_token_at(&tokens, 10, 9, TokenType::Property, "sink");
assert_token_at(&tokens, 10, 16, TokenType::Type, "Sink");
}
#[test]
fn test_occurrence_definition() {
let source = r#"occurrence def Event;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Occurrence definition ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 15, TokenType::Type, "Event");
}
#[test]
fn test_use_case() {
let source = r#"use case def DriveVehicle {
subject vehicle : Vehicle;
actor driver : Person;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Use case ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 13, TokenType::Type, "DriveVehicle");
}
#[test]
fn test_verification_case() {
let source = r#"requirement def TestReq;
verification def TestVerification {
subject testSubject;
objective verifyReq : TestReq;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Verification case ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 16, TokenType::Type, "TestReq");
assert_token_at(&tokens, 2, 17, TokenType::Type, "TestVerification");
}
#[test]
fn test_concern_usage() {
let source = r#"concern def SafetyConcern;
concern myConcern : SafetyConcern;"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== Concern usage ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 0, 12, TokenType::Type, "SafetyConcern");
assert_token_at(&tokens, 1, 8, TokenType::Property, "myConcern");
assert_token_at(&tokens, 1, 20, TokenType::Type, "SafetyConcern");
}
#[test]
fn test_cross_file_three_file_chain() {
let files = &[
(
"a.sysml",
r#"package A {
part def BaseComponent;
}"#,
),
(
"b.sysml",
r#"package B {
import A::*;
part def MiddleComponent :> BaseComponent;
}"#,
),
(
"c.sysml",
r#"package C {
import B::*;
part def FinalComponent :> MiddleComponent;
part final : FinalComponent;
}"#,
),
];
let workspace = create_multi_file_workspace(files);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "c.sysml");
println!("=== Three file chain ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 3, 13, TokenType::Type, "FinalComponent");
assert_token_at(
&tokens,
3,
31,
TokenType::Type,
"MiddleComponent (cross-file)",
);
assert_token_at(&tokens, 4, 9, TokenType::Property, "final");
assert_token_at(&tokens, 4, 17, TokenType::Type, "FinalComponent");
}
#[test]
fn test_cross_file_circular_import() {
let files = &[
(
"types_a.sysml",
r#"package TypesA {
import TypesB::*;
part def ComponentA {
part b : ComponentB;
}
}"#,
),
(
"types_b.sysml",
r#"package TypesB {
import TypesA::*;
part def ComponentB {
part a : ComponentA;
}
}"#,
),
];
let workspace = create_multi_file_workspace(files);
let tokens_a = SemanticTokenCollector::collect_from_workspace(&workspace, "types_a.sysml");
let tokens_b = SemanticTokenCollector::collect_from_workspace(&workspace, "types_b.sysml");
println!("=== Circular import - file A ===");
for t in &tokens_a {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
println!("=== Circular import - file B ===");
for t in &tokens_b {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert!(!tokens_a.is_empty(), "File A should have tokens");
assert!(!tokens_b.is_empty(), "File B should have tokens");
}
#[test]
fn test_cross_file_reexport() {
let files = &[
(
"core.sysml",
r#"package Core {
part def CoreType;
}"#,
),
(
"wrapper.sysml",
r#"package Wrapper {
public import Core::*;
}"#,
),
(
"consumer.sysml",
r#"package Consumer {
import Wrapper::*;
part myCore : CoreType;
}"#,
),
];
let workspace = create_multi_file_workspace(files);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "consumer.sysml");
println!("=== Re-export chain ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 3, 9, TokenType::Property, "myCore");
assert_token_at(&tokens, 3, 18, TokenType::Type, "CoreType (re-exported)");
}
#[test]
fn test_cross_file_mixed_relationships() {
let files = &[
(
"base.sysml",
r#"package Base {
part def Vehicle {
part engine;
port fuelPort;
}
}"#,
),
(
"electric.sysml",
r#"package Electric {
import Base::*;
part def ElectricMotor;
port def ChargingPort;
part def ElectricVehicle :> Vehicle {
part :>> engine : ElectricMotor;
port :>> fuelPort : ChargingPort;
}
}"#,
),
];
let workspace = create_multi_file_workspace(files);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "electric.sysml");
println!("=== Cross-file mixed relationships ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(&tokens, 6, 13, TokenType::Type, "ElectricVehicle");
assert_token_at(&tokens, 6, 32, TokenType::Type, "Vehicle (cross-file)");
assert_token_at(
&tokens,
7,
17,
TokenType::Property,
"engine (cross-file redefinition)",
);
assert_token_at(&tokens, 7, 26, TokenType::Type, "ElectricMotor");
assert_token_at(
&tokens,
8,
17,
TokenType::Property,
"fuelPort (cross-file redefinition)",
);
assert_token_at(&tokens, 8, 28, TokenType::Type, "ChargingPort");
}
#[test]
fn test_requirement_derivation_sysml_pattern() {
let source = r#"metadata def OriginalRequirementMetadata {
:> annotatedElement : SysML::Usage;
:>> baseType = originalRequirements meta SysML::Usage;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== RequirementDerivation pattern tokens ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(
&tokens,
0,
13,
TokenType::Type,
"OriginalRequirementMetadata (definition)",
);
assert_token_at(
&tokens,
1,
4,
TokenType::Property,
"annotatedElement (subsetting target)",
);
assert_token_at(&tokens, 1, 23, TokenType::Type, "SysML::Usage (typing)");
assert_token_at(
&tokens,
2,
5,
TokenType::Property,
"baseType (redefinition target)",
);
assert_token_at(
&tokens,
2,
42,
TokenType::Type,
"SysML::Usage (meta typing)",
);
}
#[test]
fn test_requirement_derivation_all_metadata_defs() {
let source = r#"metadata def OriginalRequirementMetadata {
:> annotatedElement : SysML::Usage;
:>> baseType = originalRequirements meta SysML::Usage;
}
metadata def DerivedRequirementMetadata {
:> annotatedElement : SysML::Usage;
:>> baseType = derivedRequirements meta SysML::Usage;
}
metadata def DerivationMetadata {
:> annotatedElement : SysML::ConnectionDefinition;
:> annotatedElement : SysML::ConnectionUsage;
:>> baseType = derivations meta SysML::Usage;
}"#;
let workspace = create_workspace(source);
let tokens = SemanticTokenCollector::collect_from_workspace(&workspace, "test.sysml");
println!("=== All RequirementDerivation metadata tokens ===");
for t in &tokens {
println!(
" Line {}, Col {}, Len {}: {:?}",
t.line, t.column, t.length, t.token_type
);
}
assert_token_at(
&tokens,
0,
13,
TokenType::Type,
"OriginalRequirementMetadata",
);
assert_token_at(
&tokens,
5,
13,
TokenType::Type,
"DerivedRequirementMetadata",
);
assert_token_at(&tokens, 10, 13, TokenType::Type, "DerivationMetadata");
let line1_tokens: Vec<_> = tokens.iter().filter(|t| t.line == 1).collect();
println!("Line 1 tokens: {:?}", line1_tokens);
assert!(
line1_tokens
.iter()
.any(|t| t.token_type == TokenType::Type && t.length == 12),
"Line 1 should have SysML::Usage (12 chars) as Type token"
);
let line6_tokens: Vec<_> = tokens.iter().filter(|t| t.line == 6).collect();
println!("Line 6 tokens: {:?}", line6_tokens);
assert!(
line6_tokens
.iter()
.any(|t| t.token_type == TokenType::Type && t.length == 12),
"Line 6 should have SysML::Usage (12 chars) as Type token"
);
let line11_tokens: Vec<_> = tokens.iter().filter(|t| t.line == 11).collect();
println!("Line 11 tokens: {:?}", line11_tokens);
assert!(
line11_tokens
.iter()
.any(|t| t.token_type == TokenType::Type && t.length == 27),
"Line 11 should have SysML::ConnectionDefinition (27 chars) as Type token"
);
let line12_tokens: Vec<_> = tokens.iter().filter(|t| t.line == 12).collect();
println!("Line 12 tokens: {:?}", line12_tokens);
assert!(
line12_tokens
.iter()
.any(|t| t.token_type == TokenType::Type && t.length == 22),
"Line 12 should have SysML::ConnectionUsage (22 chars) as Type token"
);
}