diff --git a/validation/core/BUILD b/validation/core/BUILD index 2edf1253..ef392594 100644 --- a/validation/core/BUILD +++ b/validation/core/BUILD @@ -58,6 +58,7 @@ rust_library( "src/results/mod.rs", "src/validators/bazel_component_validator.rs", "src/validators/class_design_implementation_validator.rs", + "src/validators/class_design_sequence_validator.rs", "src/validators/component_internal_api_validator.rs", "src/validators/component_public_api_validator.rs", "src/validators/component_sequence_validator.rs", @@ -66,6 +67,7 @@ rust_library( "src/validators/shared/diagram_analysis.rs", "src/validators/shared/helpers.rs", "src/validators/shared/mod.rs", + "src/validators/test/class_design_sequence_validator_test.rs", "src/validators/test/component_internal_api_validator_test.rs", "src/validators/test/component_public_api_validator_test.rs", "src/validators/test/component_sequence_validator_test.rs", diff --git a/validation/core/docs/specifications/class_design_sequence.md b/validation/core/docs/specifications/class_design_sequence.md index 8d501b76..b109744c 100644 --- a/validation/core/docs/specifications/class_design_sequence.md +++ b/validation/core/docs/specifications/class_design_sequence.md @@ -50,6 +50,35 @@ to exactly one class in the design class model. This check validates that the sequence does not reference unknown or ambiguous classes. +Participant resolution shall follow this order: + +1. Match the participant reference itself against a class id. +2. If the participant has a different display name, match that display name + against a class id. +3. If the display name still does not resolve, match the display name against a + unique class short name. +4. If the display name uses one supported special form, derive additional class + candidates from that form. +5. If none of the above resolves uniquely, fall back to matching the + participant reference against a unique class short name. + +The supported special display forms are: + +- `:Name`, which contributes `Name` as a short-name candidate. +- `prefix:qualified::Type`, which contributes `qualified::Type` as an id + candidate and both `qualified::Type` and `Type` as short-name candidates. + +Only the first non-empty display line participates in class matching. If the +display name contains additional non-empty lines or escaped line fragments +after the primary line, they shall be ignored for matching and may be reported +through debug or warning output. + +The following participant display forms are invalid and shall be rejected as +participant-class failures: + +- a primary display line containing more than one standalone `:` separator +- a primary display line containing `:` without a non-empty right-hand side + ```text ' class diagram class Controller @@ -74,6 +103,21 @@ resolve either on the target class itself or on inherited operations available through its base classes or interfaces. The sequence may only invoke behavior that the class design actually declares or inherits. +Operation lookup shall follow these rules: + +1. Check the target class itself for a method with the requested name. +2. If not found locally, traverse outgoing `Inheritance` and `Implementation` + relations recursively. +3. Track visited class ids while traversing to avoid infinite recursion caused + by cycles in the resolved relationship graph. +4. Treat inherited `private` methods as not accessible to the target class. +5. Treat inherited non-`private` methods as valid matches. + +As a result, a sequence call is valid when the target class declares the method +itself or inherits an accessible method from a base class or implemented +interface. A method that exists only as a private inherited member shall not be +accepted as a valid target operation. + ```text ' class diagram class Repository { @@ -104,8 +148,10 @@ Controller -> Controller : Validate() |---|---| | Sequence participant has no matching design class | Participant-Class Consistency | | Sequence participant matches multiple design classes ambiguously | Participant-Class Consistency | -| Sequence message targets a class that does not declare the called operation | Message-Operation Consistency | -| Sequence self-call targets a class that does not declare the called operation | Message-Operation Consistency | +| Sequence participant uses a disallowed special display form | Participant-Class Consistency | +| Sequence message targets a class that does not declare or accessibly inherit the called operation | Message-Operation Consistency | +| Sequence self-call targets a class that does not declare or accessibly inherit the called operation | Message-Operation Consistency | +| Sequence message targets a method that exists only as a private inherited operation | Message-Operation Consistency | ## Debug Output diff --git a/validation/core/integration_test/class_design_sequence/BUILD b/validation/core/integration_test/class_design_sequence/BUILD new file mode 100644 index 00000000..9ed70d42 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/BUILD @@ -0,0 +1,53 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_rust//rust:defs.bzl", "rust_test") + +filegroup( + name = "class_design_sequence_test_data", + srcs = [ + "//validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name:case_data", + "//validation/core/integration_test/class_design_sequence/negative_participant_method_missing:case_data", + "//validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion:case_data", + "//validation/core/integration_test/class_design_sequence/negative_participant_missing:case_data", + "//validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion:case_data", + "//validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method:case_data", + "//validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix:case_data", + "//validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons:case_data", + "//validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match:case_data", + "//validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match:case_data", + "//validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match:case_data", + "//validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match:case_data", + "//validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match:case_data", + "//validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match:case_data", + "//validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match:case_data", + "//validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match:case_data", + "//validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match:case_data", + "//validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match:case_data", + ], +) + +rust_test( + name = "class_design_sequence_integration_test", + srcs = ["class_design_sequence_suite.rs"], + crate_root = "class_design_sequence_suite.rs", + data = [ + ":class_design_sequence_test_data", + ], + deps = [ + "//validation/core:validation_cli", + "//validation/core/integration_test:test_framework", + "@crates//:serde", + "@crates//:serde_json", + ], +) diff --git a/validation/core/integration_test/class_design_sequence/class_design_sequence_suite.rs b/validation/core/integration_test/class_design_sequence/class_design_sequence_suite.rs new file mode 100644 index 00000000..774cdcef --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/class_design_sequence_suite.rs @@ -0,0 +1,142 @@ +// ******************************************************************************* +// Copyright (c) 2026 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License Version 2.0 which is available at +// +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +use test_framework::{ + assert_cli_result, collect_case_fbs_files, load_expected_yaml_fixture, normalize_yaml_result, + run_validation_profile, CliRunResult, +}; + +const SUITE_DIR: &str = "class_design_sequence"; + +fn run_case_from_cli( + case_dir: &str, + design_class_fbs_paths: &[String], + sequence_fbs_paths: &[String], +) -> CliRunResult { + run_validation_profile( + &format!("class_design_sequence_{case_dir}"), + "unit", + serde_json::json!({ + "design_classes": design_class_fbs_paths, + "sequence_diagrams": sequence_fbs_paths, + }), + ) +} + +fn assert_case(case_dir: &str) { + let expected = load_expected_yaml_fixture(SUITE_DIR, case_dir); + let design_class_fbs_paths = collect_case_fbs_files(SUITE_DIR, case_dir, "unit_design_class"); + let sequence_fbs_paths = collect_case_fbs_files(SUITE_DIR, case_dir, "unit_design_sequence"); + + let result = if !design_class_fbs_paths.is_empty() && !sequence_fbs_paths.is_empty() { + run_case_from_cli(case_dir, &design_class_fbs_paths, &sequence_fbs_paths) + } else { + panic!( + "missing generated FBS fixtures for {case_dir}: expected at least one unit_design_class/*.fbs.bin and unit_design_sequence/*.fbs.bin", + ); + }; + + let result = normalize_yaml_result(result); + + assert_cli_result(case_dir, &expected, &result); +} + +#[test] +fn positive_participant_abstract_base_method_match_suite_case() { + assert_case("positive_participant_abstract_base_method_match"); +} + +#[test] +fn positive_participant_multilevel_inherited_method_match_suite_case() { + assert_case("positive_participant_multilevel_inherited_method_match"); +} + +#[test] +fn positive_participant_alias_display_name_class_name_match_suite_case() { + assert_case("positive_participant_alias_display_name_class_name_match"); +} + +#[test] +fn positive_participant_alias_display_name_namespace_match_suite_case() { + assert_case("positive_participant_alias_display_name_namespace_match"); +} + +#[test] +fn positive_participant_namespace_callee_method_match_suite_case() { + assert_case("positive_participant_namespace_callee_method_match"); +} + +#[test] +fn positive_participant_short_name_namespace_match_suite_case() { + assert_case("positive_participant_short_name_namespace_match"); +} + +#[test] +fn positive_participant_special_display_leading_colon_short_name_match_suite_case() { + assert_case("positive_participant_special_display_leading_colon_short_name_match"); +} + +#[test] +fn positive_participant_special_display_qualified_type_match_suite_case() { + assert_case("positive_participant_special_display_qualified_type_match"); +} + +#[test] +fn positive_participant_special_display_short_type_match_suite_case() { + assert_case("positive_participant_special_display_short_type_match"); +} + +#[test] +fn positive_participant_special_display_encoded_newline_match_suite_case() { + assert_case("positive_participant_special_display_encoded_newline_match"); +} + +#[test] +fn negative_participant_missing_suite_case() { + assert_case("negative_participant_missing"); +} + +#[test] +fn negative_participant_ambiguous_short_name_suite_case() { + assert_case("negative_participant_ambiguous_short_name"); +} + +#[test] +fn negative_participant_method_missing_suite_case() { + assert_case("negative_participant_method_missing"); +} + +#[test] +fn negative_participant_method_missing_with_suggestion_suite_case() { + assert_case("negative_participant_method_missing_with_suggestion"); +} + +#[test] +fn negative_participant_private_inherited_method_suite_case() { + assert_case("negative_participant_private_inherited_method"); +} + +#[test] +fn negative_participant_missing_with_suggestion_suite_case() { + assert_case("negative_participant_missing_with_suggestion"); +} + +#[test] +fn negative_participant_special_display_multiple_colons_suite_case() { + assert_case("negative_participant_special_display_multiple_colons"); +} + +#[test] +fn negative_participant_special_display_empty_suffix_suite_case() { + assert_case("negative_participant_special_display_empty_suffix"); +} diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/BUILD b/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/class_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/class_diagram.puml new file mode 100644 index 00000000..d4c5d3d7 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/class_diagram.puml @@ -0,0 +1,28 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +namespace unit_1 { + class Controller { + + Execute() : void + } +} + +namespace unit_2 { + class Controller { + + Execute() : void + } +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/expected.yaml b/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/expected.yaml new file mode 100644 index 00000000..ae97a157 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/expected.yaml @@ -0,0 +1,20 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: false +error_contains: | + [Class] Sequence participant "Controller" matches multiple classes in the class diagram. + Participant : "Controller" + Matching classes : "unit_1.Controller", "unit_2.Controller" + Sequence source file : "validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/sequence_diagram.puml" + Sequence source line : 16 + Fix : Rename participant "Controller" in the sequence diagram to a unique class id, or rename one of the matching classes in the class diagram. diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/sequence_diagram.puml new file mode 100644 index 00000000..327c0a62 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_ambiguous_short_name/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant Controller + +Controller -> Controller : Execute() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/BUILD b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/class_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/class_diagram.puml new file mode 100644 index 00000000..e659419d --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/class_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +class Repository { + + Store() : void +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/expected.yaml b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/expected.yaml new file mode 100644 index 00000000..850bc08d --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/expected.yaml @@ -0,0 +1,20 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: false +error_contains: | + [Method] Sequence function "FindById" from sequence call "Repository" -> "Repository" : "FindById" not found on target class "Repository" or its accessible inherited types in the class diagram. + Sequence call : "Repository" -> "Repository" : "FindById" + Target class : "Repository" + Sequence source file : "validation/core/integration_test/class_design_sequence/negative_participant_method_missing/sequence_diagram.puml" + Sequence source line : 18 + Fix : Add method "FindById" to class "Repository" or one of its accessible inherited types in the class diagram, or change or remove that sequence call. diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/sequence_diagram.puml new file mode 100644 index 00000000..96a72e6a --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant Repository + +Repository -> Repository : FindById() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/BUILD b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/class_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/class_diagram.puml new file mode 100644 index 00000000..279b84be --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/class_diagram.puml @@ -0,0 +1,26 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +abstract class RepositoryBase { + + FindById() : void +} + +class Repository { + + Store() : void +} + +RepositoryBase <|-- Repository + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/expected.yaml b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/expected.yaml new file mode 100644 index 00000000..15344dd7 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/expected.yaml @@ -0,0 +1,21 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: false +error_contains: | + [Method] Sequence function "FindByIds" from sequence call "Repository" -> "Repository" : "FindByIds" not found on target class "Repository" or its accessible inherited types in the class diagram. + Sequence call : "Repository" -> "Repository" : "FindByIds" + Target class : "Repository" + Sequence source file : "validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/sequence_diagram.puml" + Sequence source line : 18 + Suggestion for "FindByIds" : Did you mean method "FindById"? + Fix : Add method "FindByIds" to class "Repository" or one of its accessible inherited types in the class diagram, or change or remove that sequence call. diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/sequence_diagram.puml new file mode 100644 index 00000000..3041c552 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_method_missing_with_suggestion/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant Repository + +Repository -> Repository : FindByIds() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_missing/BUILD b/validation/core/integration_test/class_design_sequence/negative_participant_missing/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_missing/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_missing/class_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_missing/class_diagram.puml new file mode 100644 index 00000000..7dca3c5f --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_missing/class_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +class Controller { + + Execute() : void +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_missing/expected.yaml b/validation/core/integration_test/class_design_sequence/negative_participant_missing/expected.yaml new file mode 100644 index 00000000..1a111261 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_missing/expected.yaml @@ -0,0 +1,19 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: false +error_contains: | + [Class] Sequence participant "Repository" has no matching class in the class diagram. + Participant : "Repository" + Sequence source file : "validation/core/integration_test/class_design_sequence/negative_participant_missing/sequence_diagram.puml" + Sequence source line : 16 + Fix : Add class "Repository" to the class diagram, or remove the participant from the sequence diagram. diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_missing/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_missing/sequence_diagram.puml new file mode 100644 index 00000000..fae3055c --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_missing/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant Repository + +Repository -> Repository : Execute() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/BUILD b/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/class_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/class_diagram.puml new file mode 100644 index 00000000..26889ac6 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/class_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +class Repository { + + Execute() : void +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/expected.yaml b/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/expected.yaml new file mode 100644 index 00000000..ec9992d4 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/expected.yaml @@ -0,0 +1,20 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: false +error_contains: | + [Class] Sequence participant "Repositry" has no matching class in the class diagram. + Participant : "Repositry" + Sequence source file : "validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/sequence_diagram.puml" + Sequence source line : 16 + Suggestion for "Repositry" : Did you mean class "Repository"? + Fix : Add class "Repositry" to the class diagram, or remove the participant from the sequence diagram. diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/sequence_diagram.puml new file mode 100644 index 00000000..a96996fc --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_missing_with_suggestion/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant Repositry + +Repositry -> Repositry : Execute() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/BUILD b/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/class_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/class_diagram.puml new file mode 100644 index 00000000..0211710b --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/class_diagram.puml @@ -0,0 +1,26 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +class BaseStore { + - LoadState() : void +} + +class StateStore { + + SaveState() : void +} + +BaseStore <|-- StateStore + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/expected.yaml b/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/expected.yaml new file mode 100644 index 00000000..f7861b4a --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/expected.yaml @@ -0,0 +1,20 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: false +error_contains: | + [Method] Sequence function "LoadState" from sequence call "StateStore" -> "StateStore" : "LoadState" exists only as a private inherited method on target class "StateStore" in the class diagram. + Sequence call : "StateStore" -> "StateStore" : "LoadState" + Target class : "StateStore" + Sequence source file : "validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/sequence_diagram.puml" + Sequence source line : 18 + Fix : Consider changing method "LoadState" to public or protected on an inherited type of class "StateStore", add an accessible wrapper on that class, or change or remove that sequence call. diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/sequence_diagram.puml new file mode 100644 index 00000000..d8ec8abc --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_private_inherited_method/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant StateStore + +StateStore -> StateStore : LoadState() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/BUILD b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/class_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/class_diagram.puml new file mode 100644 index 00000000..be9fcad7 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/class_diagram.puml @@ -0,0 +1,18 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +class Runtime + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/expected.yaml b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/expected.yaml new file mode 100644 index 00000000..9185e237 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/expected.yaml @@ -0,0 +1,21 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: false +error_contains: |- + [Class] Sequence participant "singletonInstance:" uses an invalid kind of display name. + Participant : "singletonInstance:" + Display name : "singletonInstance:" + Invalid form : "singletonInstance:" uses ':' without a non-empty right-hand side + Sequence source file : "validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/sequence_diagram.puml" + Sequence source line : 16 + Fix : Use one supported form such as :Name, prefix:qualified::Type, or provide an unambiguous alias. diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/sequence_diagram.puml new file mode 100644 index 00000000..6b00f453 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_empty_suffix/sequence_diagram.puml @@ -0,0 +1,18 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant "singletonInstance:" + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/BUILD b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/class_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/class_diagram.puml new file mode 100644 index 00000000..92441dc6 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/class_diagram.puml @@ -0,0 +1,26 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +namespace score { + namespace mw { + namespace com { + namespace impl { + class Runtime + } + } + } +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/expected.yaml b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/expected.yaml new file mode 100644 index 00000000..a481fcfb --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/expected.yaml @@ -0,0 +1,21 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: false +error_contains: | + [Class] Sequence participant "instance:score::mw::com::impl::Runtime:Impl" uses an invalid kind of display name. + Participant : "instance:score::mw::com::impl::Runtime:Impl" + Display name : "instance:score::mw::com::impl::Runtime:Impl" + Invalid form : "instance:score::mw::com::impl::Runtime:Impl" contains multiple standalone ':' separators + Sequence source file : "validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/sequence_diagram.puml" + Sequence source line : 16 + Fix : Use one supported form such as :Name, prefix:qualified::Type, or provide an unambiguous alias. diff --git a/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/sequence_diagram.puml new file mode 100644 index 00000000..f2324391 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/negative_participant_special_display_multiple_colons/sequence_diagram.puml @@ -0,0 +1,18 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant "instance:score::mw::com::impl::Runtime:Impl" + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/BUILD b/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/class_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/class_diagram.puml new file mode 100644 index 00000000..32c0f10f --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/class_diagram.puml @@ -0,0 +1,26 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +abstract class ReadCapabilityBase { + + LoadState() : void +} + +class StateStore { + + SaveState() : void +} + +ReadCapabilityBase <|-- StateStore + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/expected.yaml b/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/expected.yaml new file mode 100644 index 00000000..898ecba3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/expected.yaml @@ -0,0 +1,13 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: true diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/sequence_diagram.puml new file mode 100644 index 00000000..d8ec8abc --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_abstract_base_method_match/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant StateStore + +StateStore -> StateStore : LoadState() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/BUILD b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/class_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/class_diagram.puml new file mode 100644 index 00000000..1668e090 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/class_diagram.puml @@ -0,0 +1,22 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +namespace A { + class Repository { + + FindById() : void + } +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/expected.yaml b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/expected.yaml new file mode 100644 index 00000000..898ecba3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/expected.yaml @@ -0,0 +1,13 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: true diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/sequence_diagram.puml new file mode 100644 index 00000000..0c5bc953 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_class_name_match/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant "Repository" as Repo + +Repo -> Repo : FindById() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/BUILD b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/class_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/class_diagram.puml new file mode 100644 index 00000000..9725a38f --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/class_diagram.puml @@ -0,0 +1,22 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +namespace unit_1 { + class Controller { + + Execute() : void + } +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/expected.yaml b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/expected.yaml new file mode 100644 index 00000000..898ecba3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/expected.yaml @@ -0,0 +1,13 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: true diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/sequence_diagram.puml new file mode 100644 index 00000000..e2dba124 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_alias_display_name_namespace_match/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant "unit_1::Controller" as controller + +controller -> controller : Execute() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/BUILD b/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/class_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/class_diagram.puml new file mode 100644 index 00000000..3d2fb535 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/class_diagram.puml @@ -0,0 +1,31 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +class RootStore { + + LoadState() : void +} + +class IntermediateStore { + + RefreshCache() : void +} + +class StateStore { + + SaveState() : void +} + +RootStore <|-- IntermediateStore +IntermediateStore <|-- StateStore + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/expected.yaml b/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/expected.yaml new file mode 100644 index 00000000..898ecba3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/expected.yaml @@ -0,0 +1,13 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: true diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/sequence_diagram.puml new file mode 100644 index 00000000..d8ec8abc --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_multilevel_inherited_method_match/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant StateStore + +StateStore -> StateStore : LoadState() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/BUILD b/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/class_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/class_diagram.puml new file mode 100644 index 00000000..a88b9122 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/class_diagram.puml @@ -0,0 +1,27 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +class Controller { + + HandleRequest() : void +} + +namespace unit_1 { + class StateStore { + + LoadState() : void + + SaveState() : void + } +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/expected.yaml b/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/expected.yaml new file mode 100644 index 00000000..898ecba3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/expected.yaml @@ -0,0 +1,13 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: true diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/sequence_diagram.puml new file mode 100644 index 00000000..548269a3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_namespace_callee_method_match/sequence_diagram.puml @@ -0,0 +1,21 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant Controller +participant "unit_1::StateStore" as StateStore + +Controller -> StateStore : LoadState() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/BUILD b/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/class_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/class_diagram.puml new file mode 100644 index 00000000..1668e090 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/class_diagram.puml @@ -0,0 +1,22 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +namespace A { + class Repository { + + FindById() : void + } +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/expected.yaml b/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/expected.yaml new file mode 100644 index 00000000..898ecba3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/expected.yaml @@ -0,0 +1,13 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: true diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/sequence_diagram.puml new file mode 100644 index 00000000..96a72e6a --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_short_name_namespace_match/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant Repository + +Repository -> Repository : FindById() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/BUILD b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/class_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/class_diagram.puml new file mode 100644 index 00000000..c7846db4 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/class_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +class Process { + + Execute() : void +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/expected.yaml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/expected.yaml new file mode 100644 index 00000000..898ecba3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/expected.yaml @@ -0,0 +1,13 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: true diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/sequence_diagram.puml new file mode 100644 index 00000000..d0d83fe1 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_encoded_newline_match/sequence_diagram.puml @@ -0,0 +1,20 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant ":Process/nara::com user" as help + +help -> help : Execute() + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/BUILD b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/class_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/class_diagram.puml new file mode 100644 index 00000000..aada9971 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/class_diagram.puml @@ -0,0 +1,18 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +class OS + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/expected.yaml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/expected.yaml new file mode 100644 index 00000000..898ecba3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/expected.yaml @@ -0,0 +1,13 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: true diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/sequence_diagram.puml new file mode 100644 index 00000000..4d9c33d9 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_leading_colon_short_name_match/sequence_diagram.puml @@ -0,0 +1,18 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant ":OS" + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/BUILD b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/class_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/class_diagram.puml new file mode 100644 index 00000000..8a607ddf --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/class_diagram.puml @@ -0,0 +1,26 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +namespace score { + namespace mw { + namespace com { + namespace impl { + class Runtime + } + } + } +} + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/expected.yaml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/expected.yaml new file mode 100644 index 00000000..898ecba3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/expected.yaml @@ -0,0 +1,13 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: true diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/sequence_diagram.puml new file mode 100644 index 00000000..418da8fb --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_qualified_type_match/sequence_diagram.puml @@ -0,0 +1,18 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant "singletonInstance:score::mw::com::impl::Runtime" + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/BUILD b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/BUILD new file mode 100644 index 00000000..30f3d121 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//bazel/rules/rules_score:rules_score.bzl", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + dynamic = ["sequence_diagram.puml"], + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":unit_design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/class_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/class_diagram.puml new file mode 100644 index 00000000..be9fcad7 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/class_diagram.puml @@ -0,0 +1,18 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml class_diagram + +class Runtime + +@enduml diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/expected.yaml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/expected.yaml new file mode 100644 index 00000000..898ecba3 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/expected.yaml @@ -0,0 +1,13 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +should_pass: true diff --git a/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/sequence_diagram.puml b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/sequence_diagram.puml new file mode 100644 index 00000000..1994b331 --- /dev/null +++ b/validation/core/integration_test/class_design_sequence/positive_participant_special_display_short_type_match/sequence_diagram.puml @@ -0,0 +1,18 @@ +' ******************************************************************************* +' Copyright (c) 2026 Contributors to the Eclipse Foundation +' +' See the NOTICE file(s) distributed with this work for additional +' information regarding copyright ownership. +' +' This program and the accompanying materials are made available under the +' terms of the Apache License Version 2.0 which is available at +' https://www.apache.org/licenses/LICENSE-2.0 +' +' SPDX-License-Identifier: Apache-2.0 +' ******************************************************************************* + +@startuml sequence_diagram + +participant "singletonInstance:Runtime" + +@enduml diff --git a/validation/core/src/models/mod.rs b/validation/core/src/models/mod.rs index e0d31986..221543e5 100644 --- a/validation/core/src/models/mod.rs +++ b/validation/core/src/models/mod.rs @@ -33,4 +33,5 @@ pub use component_diagram_models::{ }; pub use sequence_diagram_models::{ is_external_endpoint, ObservedSequenceCall, SequenceDiagramIndex, SequenceDiagramInputs, + SequenceParticipantInfo, }; diff --git a/validation/core/src/models/sequence_diagram_models.rs b/validation/core/src/models/sequence_diagram_models.rs index 73cae587..aab9a207 100644 --- a/validation/core/src/models/sequence_diagram_models.rs +++ b/validation/core/src/models/sequence_diagram_models.rs @@ -38,6 +38,66 @@ pub struct ObservedSequenceCall { pub source_location: SourceLocation, } +/// Validation-only participant metadata keyed by the participant reference name +/// used in sequence interactions. +pub struct SequenceParticipantInfo { + pub display_name: String, + pub source_location: SourceLocation, +} + +impl SequenceParticipantInfo { + // TODO: Remove this normalization once class diagram identifiers also use + // `::` namespaces directly instead of `.`. + pub fn normalize_qualified_name(reference: &str) -> String { + reference.replace("::", ".") + } +} + +fn strip_supported_html_style_tags(text: &str) -> String { + let mut normalized = String::new(); + let mut index = 0; + + while index < text.len() { + let remaining = &text[index..]; + + if let Some(tag_len) = supported_html_style_tag_length(remaining) { + index += tag_len; + continue; + } + + let ch = remaining.chars().next().expect("remaining is non-empty"); + normalized.push(ch); + index += ch.len_utf8(); + } + + normalized +} + +fn supported_html_style_tag_length(text: &str) -> Option { + if !text.starts_with('<') { + return None; + } + + let end = text.find('>')?; + let tag = text[1..end].trim().to_ascii_lowercase(); + + let known_tags = [ + "b", "/b", "i", "/i", "u", "/u", "s", "/s", "w", "/w", "img", "/img", "font", "/font", + ]; + let styled_tags = ["color", "back", "size"]; + + let is_known_tag = known_tags.contains(&tag.as_str()); + let is_styled_tag = styled_tags.iter().any(|styled_tag| { + tag == format!("/{styled_tag}") || tag.starts_with(&format!("{styled_tag}:")) + }); + + if is_known_tag || is_styled_tag { + Some(end + 1) + } else { + None + } +} + impl SequenceDiagramInputs { /// Build a [`SequenceDiagramIndex`] from sequence diagram inputs. pub fn to_sequence_diagram_index(&self, result: &mut ValidationResult) -> SequenceDiagramIndex { @@ -47,7 +107,7 @@ impl SequenceDiagramInputs { /// Indexed sequence-diagram data prepared for validators. pub struct SequenceDiagramIndex { - participants: BTreeMap, + participants: BTreeMap, observed_calls: Vec, } @@ -68,7 +128,10 @@ impl SequenceDiagramIndex { // declared in more than one input diagram. participants .entry(reference_name) - .or_insert_with(|| participant.source_location.clone()); + .or_insert_with(|| SequenceParticipantInfo { + display_name: strip_supported_html_style_tags(&participant.display_name), + source_location: participant.source_location.clone(), + }); } collect_block_data(&diagram.root, &mut observed_calls, result); @@ -80,10 +143,18 @@ impl SequenceDiagramIndex { } } - pub fn participants(&self) -> &BTreeMap { + pub fn participants(&self) -> &BTreeMap { &self.participants } + pub fn declared_participants(&self) -> impl Iterator { + self.participants.keys().map(String::as_str) + } + + pub fn participant_info(&self, participant: &str) -> Option<&SequenceParticipantInfo> { + self.participants.get(participant) + } + pub fn observed_calls(&self) -> &[ObservedSequenceCall] { &self.observed_calls } diff --git a/validation/core/src/profiles/unit.rs b/validation/core/src/profiles/unit.rs index aa095f65..49e53ad1 100644 --- a/validation/core/src/profiles/unit.rs +++ b/validation/core/src/profiles/unit.rs @@ -11,21 +11,51 @@ // SPDX-License-Identifier: Apache-2.0 // ******************************************************************************* -use crate::models::{ClassDiagramInputs, ClassEntityIndex}; -use crate::readers::ClassDiagramReader; -use crate::validators::validate_class_design_implementation; +use crate::models::{ + ClassDiagramInputs, ClassEntityIndex, SequenceDiagramIndex, SequenceDiagramInputs, +}; +use crate::readers::{ClassDiagramReader, SequenceDiagramReader}; +use crate::validators::{validate_class_design_implementation, validate_class_design_sequence}; use crate::ValidationResult; use serde::Deserialize; use super::profile::{merge_results, read_and_convert, ProfileRun}; +type ProfileValidator<'a> = Box Option + 'a>; + #[derive(Default, Deserialize)] #[serde(default, deny_unknown_fields)] pub struct UnitInputs { design_classes: Vec, + sequence_diagrams: Vec, implementation_classes: Vec, } +fn registered_validators<'a>( + design_classes: &'a Option, + sequence_diagrams: &'a Option, + implementation_classes: &'a Option, +) -> Vec> { + vec![ + Box::new(move || { + let (design_classes, implementation_classes) = + (design_classes.as_ref()?, implementation_classes.as_ref()?); + Some(validate_class_design_implementation( + design_classes, + implementation_classes, + )) + }), + Box::new(move || { + let (design_classes, sequence_diagrams) = + (design_classes.as_ref()?, sequence_diagrams.as_ref()?); + Some(validate_class_design_sequence( + design_classes, + sequence_diagrams, + )) + }), + ] +} + pub fn run(inputs: &UnitInputs) -> Result { let mut result = ValidationResult::default(); let design_classes = read_and_convert::( @@ -38,16 +68,21 @@ pub fn run(inputs: &UnitInputs) -> Result { &mut result, |raw: ClassDiagramInputs, errs| ClassEntityIndex::build_index(&raw, errs), )?; + let sequence_diagrams = read_and_convert::( + inputs.sequence_diagrams.as_slice(), + &mut result, + |raw: SequenceDiagramInputs, errs| raw.to_sequence_diagram_index(errs), + )?; + + let validators = + registered_validators(&design_classes, &sequence_diagrams, &implementation_classes); let mut ran_validator = false; - if let (Some(design_classes), Some(implementation_classes)) = - (design_classes.as_ref(), implementation_classes.as_ref()) - { - merge_results( - &mut result, - validate_class_design_implementation(design_classes, implementation_classes), - ); - ran_validator = true; + for validator in validators { + if let Some(validator_result) = validator() { + merge_results(&mut result, validator_result); + ran_validator = true; + } } Ok(ProfileRun { diff --git a/validation/core/src/validators/class_design_sequence_validator.rs b/validation/core/src/validators/class_design_sequence_validator.rs new file mode 100644 index 00000000..3d63f7dc --- /dev/null +++ b/validation/core/src/validators/class_design_sequence_validator.rs @@ -0,0 +1,802 @@ +// ******************************************************************************* +// Copyright (c) 2026 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License Version 2.0 which is available at +// +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +//! Validation: compare unit class-design entities with sequence-diagram usage. + +use std::collections::BTreeSet; + +use super::shared::{best_string_suggestion, extract_method_name, format_sequence_call}; +use crate::models::{ + ClassEntityIndex, ObservedSequenceCall, SequenceDiagramIndex, SequenceParticipantInfo, +}; +use crate::{Diagnostics, ErrorBuilder, ErrorCategory, ValidationResult}; +use class_diagram::{RelationType, Visibility}; + +/// Run class-design-vs-sequence validation. +pub fn validate_class_design_sequence( + design_classes: &ClassEntityIndex, + sequence_diagram: &SequenceDiagramIndex, +) -> ValidationResult { + ClassDesignSequenceValidator::new(design_classes, sequence_diagram).run() +} + +struct ClassDesignSequenceValidator<'a> { + design_classes: &'a ClassEntityIndex, + sequence_diagram: &'a SequenceDiagramIndex, + result: ValidationResult, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum MethodLookupResult { + FoundAccessible, + FoundPrivateInherited, + NotFound, +} + +impl<'a> ClassDesignSequenceValidator<'a> { + fn new( + design_classes: &'a ClassEntityIndex, + sequence_diagram: &'a SequenceDiagramIndex, + ) -> Self { + Self { + design_classes, + sequence_diagram, + result: ValidationResult::default(), + } + } + + fn run(mut self) -> ValidationResult { + append_debug_log( + &mut self.result.diagnostics, + self.design_classes, + self.sequence_diagram, + ); + self.check_participant_class_consistency(); + self.check_message_operation_consistency(); + self.result + } + + fn check_participant_class_consistency(&mut self) { + for (participant, participant_info) in self.sequence_diagram.participants() { + self.validate_participant(participant, participant_info); + } + } + + fn validate_participant( + &mut self, + participant: &str, + participant_info: &SequenceParticipantInfo, + ) { + let (source_file, source_line) = participant_info.source_location.display(); + + if let Some(display_issue) = unsupported_participant_display_form(participant_info) { + self.report_unsupported_participant_display_name( + participant, + participant_info, + &source_file, + source_line, + display_issue, + ); + return; + } + + self.log_ignored_special_display_suffix( + participant, + participant_info, + &source_file, + source_line, + ); + + match self.resolve_participant_class(participant) { + ParticipantResolution::Matched(_) => {} + ParticipantResolution::Missing => { + self.result.add_failure(self.missing_participant_failure( + participant, + participant_info, + &source_file, + source_line, + )) + } + ParticipantResolution::Ambiguous(matches) => { + self.result.add_failure(self.ambiguous_participant_failure( + participant, + &source_file, + source_line, + &matches, + )) + } + } + } + + fn log_ignored_special_display_suffix( + &self, + participant: &str, + participant_info: &SequenceParticipantInfo, + source_file: &str, + source_line: u32, + ) { + if let Some(ignored_suffix) = ignored_special_display_suffix(participant_info) { + log::warn!( + "sequence participant \"{}\" ignores trailing special display text \"{}\" at {}:{}; it is not treated as namespace or class matching data", + participant, + ignored_suffix, + source_file, + source_line, + ); + } + } + + fn missing_participant_failure( + &self, + participant: &str, + participant_info: &SequenceParticipantInfo, + source_file: &str, + source_line: u32, + ) -> String { + let error = ErrorBuilder::new(ErrorCategory::Class) + .title(format!( + "sequence participant \"{participant}\" has no matching class in the class diagram" + )) + .field("participant", format!("\"{participant}\"")) + .field("sequence source file", format!("\"{source_file}\"")) + .field("sequence source line", source_line.to_string()) + .fix(format!( + "add class \"{participant}\" to the class diagram, or remove the participant from the sequence diagram" + )); + + if let Some(suggested_class) = self + .best_participant_class_suggestion(participant, participant_info) + .as_deref() + { + error.suggest(participant, Some("class"), suggested_class) + } else { + error + } + .build() + } + + fn ambiguous_participant_failure( + &self, + participant: &str, + source_file: &str, + source_line: u32, + matches: &BTreeSet, + ) -> String { + ErrorBuilder::new(ErrorCategory::Class) + .title(format!( + "sequence participant \"{participant}\" matches multiple classes in the class diagram" + )) + .field("participant", format!("\"{participant}\"")) + .field("matching classes", format_name_set(matches)) + .field("sequence source file", format!("\"{source_file}\"")) + .field("sequence source line", source_line.to_string()) + .fix(format!( + "rename participant \"{participant}\" in the sequence diagram to a unique class id, or rename one of the matching classes in the class diagram" + )) + .build() + } + + fn check_message_operation_consistency(&mut self) { + for observed_call in self.sequence_diagram.observed_calls() { + self.validate_observed_call(observed_call); + } + } + + fn validate_observed_call(&mut self, observed_call: &ObservedSequenceCall) { + let ParticipantResolution::Matched(callee_class) = + self.resolve_participant_class(&observed_call.callee) + else { + return; + }; + + let method_name = extract_method_name(&observed_call.method); + if method_name.is_empty() { + return; + } + + let method_lookup = self.class_or_ancestors_define_method( + callee_class, + method_name, + false, + &mut BTreeSet::new(), + ); + if method_lookup == MethodLookupResult::FoundAccessible { + return; + } + + self.result.add_failure(self.method_lookup_failure( + observed_call, + callee_class, + method_name, + method_lookup, + )); + } + + fn method_lookup_failure( + &self, + observed_call: &ObservedSequenceCall, + callee_class: &'a class_diagram::SimpleEntity, + method_name: &str, + method_lookup: MethodLookupResult, + ) -> String { + let sequence_call = + format_sequence_call(&observed_call.caller, &observed_call.callee, method_name); + let (source_file, source_line) = observed_call.source_location.display(); + + match method_lookup { + MethodLookupResult::FoundAccessible => { + unreachable!("accessible methods should return early") + } + MethodLookupResult::FoundPrivateInherited => ErrorBuilder::new(ErrorCategory::Method) + .title(format!( + "sequence function \"{method_name}\" from sequence call {sequence_call} exists only as a private inherited method on target class \"{}\" in the class diagram", + callee_class.id, + )) + .field("sequence call", sequence_call) + .field("target class", format!("\"{}\"", callee_class.id)) + .field("sequence source file", format!("\"{source_file}\"")) + .field("sequence source line", source_line.to_string()) + .fix(format!( + "consider changing method \"{method_name}\" to public or protected on an inherited type of class \"{}\", add an accessible wrapper on that class, or change or remove that sequence call", + callee_class.id, + )) + .build(), + MethodLookupResult::NotFound => { + let error = ErrorBuilder::new(ErrorCategory::Method) + .title(format!( + "sequence function \"{method_name}\" from sequence call {sequence_call} not found on target class \"{}\" or its accessible inherited types in the class diagram", + callee_class.id, + )) + .field("sequence call", sequence_call) + .field("target class", format!("\"{}\"", callee_class.id)) + .field("sequence source file", format!("\"{source_file}\"")) + .field("sequence source line", source_line.to_string()) + .fix(format!( + "add method \"{method_name}\" to class \"{}\" or one of its accessible inherited types in the class diagram, or change or remove that sequence call", + callee_class.id, + )); + + if let Some(suggested_method) = self + .best_method_suggestion(callee_class, method_name) + .as_deref() + { + error.suggest(method_name, Some("method"), suggested_method) + } else { + error + } + .build() + } + } + } + + fn best_participant_class_suggestion( + &self, + participant: &str, + participant_info: &SequenceParticipantInfo, + ) -> Option { + let class_candidates: BTreeSet = self + .design_classes + .entities() + .flat_map(|entity| [entity.id.clone(), entity.name.clone()]) + .filter(|candidate| !candidate.is_empty()) + .collect(); + + participant_suggestion_queries(participant, participant_info) + .into_iter() + .find_map(|query| { + best_string_suggestion(&query, class_candidates.iter().map(String::as_str)) + }) + } + + fn best_method_suggestion( + &self, + callee_class: &'a class_diagram::SimpleEntity, + method_name: &str, + ) -> Option { + let mut visited_ids = BTreeSet::new(); + let mut method_candidates = BTreeSet::new(); + self.collect_related_method_names(callee_class, &mut visited_ids, &mut method_candidates); + + best_string_suggestion(method_name, method_candidates.iter().map(String::as_str)) + } + + fn resolve_participant_class(&self, participant: &str) -> ParticipantResolution<'a> { + if let Some(resolution) = self.resolve_class_from_participant(participant) { + return resolution; + } + + if let Some(participant_info) = self.sequence_diagram.participant_info(participant) { + if let Some(resolution) = self.resolve_class_from_display_name( + participant, + participant_info.display_name.as_str(), + ) { + return resolution; + } + + if let Some(resolution) = self.resolve_class_from_special_display_form(participant_info) + { + return resolution; + } + } + + self.resolve_by_class_name(participant) + } + + fn resolve_class_from_participant( + &self, + participant: &str, + ) -> Option> { + self.resolve_by_class_id(participant) + .map(ParticipantResolution::Matched) + } + + fn resolve_class_from_display_name( + &self, + participant: &str, + display_name: &str, + ) -> Option> { + if display_name == participant { + return None; + } + + if let Some(entity) = self.resolve_by_class_id(display_name) { + return Some(ParticipantResolution::Matched(entity)); + } + + match self.resolve_by_class_name(display_name) { + ParticipantResolution::Missing => None, + matched_or_ambiguous => Some(matched_or_ambiguous), + } + } + + fn resolve_class_from_special_display_form( + &self, + participant_info: &SequenceParticipantInfo, + ) -> Option> { + let display_candidates = class_match_candidates_from_display(participant_info); + + for id_candidate in display_candidates.id_candidates { + if let Some(entity) = self.resolve_by_class_id(&id_candidate) { + return Some(ParticipantResolution::Matched(entity)); + } + } + + for name_candidate in display_candidates.name_candidates { + match self.resolve_by_class_name(&name_candidate) { + ParticipantResolution::Missing => {} + matched_or_ambiguous => return Some(matched_or_ambiguous), + } + } + + None + } + + fn report_unsupported_participant_display_name( + &mut self, + participant: &str, + participant_info: &SequenceParticipantInfo, + source_file: &str, + source_line: u32, + display_issue: UnsupportedParticipantDisplayForm, + ) { + self.result.add_failure( + ErrorBuilder::new(ErrorCategory::Class) + .title(format!( + "sequence participant \"{participant}\" uses an invalid kind of display name" + )) + .field("participant", format!("\"{participant}\"")) + .field("display name", format!("\"{}\"", participant_info.display_name)) + .field( + "invalid form", + display_issue.invalid_form(&participant_info.display_name), + ) + .field("sequence source file", format!("\"{source_file}\"")) + .field("sequence source line", source_line.to_string()) + .fix( + "use one supported form such as :Name, prefix:qualified::Type, or provide an unambiguous alias" + .to_string(), + ) + .build(), + ); + } + + fn resolve_by_class_id(&self, reference: &str) -> Option<&'a class_diagram::SimpleEntity> { + if let Some(entity) = self.design_classes.find_by_id(reference) { + return Some(entity); + } + + let normalized_reference = SequenceParticipantInfo::normalize_qualified_name(reference); + if normalized_reference == reference { + return None; + } + + self.design_classes.find_by_id(&normalized_reference) + } + + fn resolve_by_class_name(&self, class_name: &str) -> ParticipantResolution<'a> { + let short_name_matches: Vec<_> = self + .design_classes + .entities() + .filter(|entity| entity.name == class_name) + .collect(); + + match short_name_matches.as_slice() { + [] => ParticipantResolution::Missing, + [entity] => ParticipantResolution::Matched(entity), + entities => ParticipantResolution::Ambiguous( + entities.iter().map(|entity| entity.id.clone()).collect(), + ), + } + } + + fn class_or_ancestors_define_method( + &self, + entity: &'a class_diagram::SimpleEntity, + method_name: &str, + inherited: bool, + visited_ids: &mut BTreeSet, + ) -> MethodLookupResult { + let local_result = Self::method_lookup_on_entity(entity, method_name, inherited); + if local_result != MethodLookupResult::NotFound { + return local_result; + } + + if !visited_ids.insert(entity.id.clone()) { + return MethodLookupResult::NotFound; + } + + self.related_parent_or_interface_defines_method(entity, method_name, visited_ids) + } + + fn method_lookup_on_entity( + entity: &'a class_diagram::SimpleEntity, + method_name: &str, + inherited: bool, + ) -> MethodLookupResult { + let mut found_private_inherited = false; + + for method in &entity.methods { + if method.name != method_name { + continue; + } + + if inherited && matches!(method.visibility, Visibility::Private) { + found_private_inherited = true; + continue; + } + + return MethodLookupResult::FoundAccessible; + } + + if found_private_inherited { + MethodLookupResult::FoundPrivateInherited + } else { + MethodLookupResult::NotFound + } + } + + fn related_parent_or_interface_defines_method( + &self, + entity: &'a class_diagram::SimpleEntity, + method_name: &str, + visited_ids: &mut BTreeSet, + ) -> MethodLookupResult { + let mut found_private_inherited = false; + + for relationship in &entity.relationships { + if relationship.source != entity.id + || !matches!( + relationship.relation_type, + RelationType::Inheritance | RelationType::Implementation + ) + { + continue; + } + + let Some(parent) = self.design_classes.find_by_id(&relationship.target) else { + continue; + }; + + match self.class_or_ancestors_define_method(parent, method_name, true, visited_ids) { + MethodLookupResult::FoundAccessible => return MethodLookupResult::FoundAccessible, + MethodLookupResult::FoundPrivateInherited => found_private_inherited = true, + MethodLookupResult::NotFound => {} + } + } + + if found_private_inherited { + MethodLookupResult::FoundPrivateInherited + } else { + MethodLookupResult::NotFound + } + } + + fn collect_related_method_names( + &self, + entity: &'a class_diagram::SimpleEntity, + visited_ids: &mut BTreeSet, + method_candidates: &mut BTreeSet, + ) { + if !visited_ids.insert(entity.id.clone()) { + return; + } + + method_candidates.extend( + entity + .methods + .iter() + .map(|method| method.name.as_str()) + .filter(|name| !name.is_empty()) + .map(str::to_string), + ); + + for relationship in &entity.relationships { + if relationship.source != entity.id + || !matches!( + relationship.relation_type, + RelationType::Inheritance | RelationType::Implementation + ) + { + continue; + } + + let Some(parent) = self.design_classes.find_by_id(&relationship.target) else { + continue; + }; + + self.collect_related_method_names(parent, visited_ids, method_candidates); + } + } +} + +enum ParticipantResolution<'a> { + Matched(&'a class_diagram::SimpleEntity), + Missing, + Ambiguous(BTreeSet), +} + +#[derive(Default)] +struct ClassMatchCandidates { + id_candidates: Vec, + name_candidates: Vec, +} + +#[derive(Clone, Copy)] +enum UnsupportedParticipantDisplayForm { + MultipleStandaloneColons, + EmptyColonSuffix, +} + +impl UnsupportedParticipantDisplayForm { + fn invalid_form(self, display_name: &str) -> String { + match self { + Self::MultipleStandaloneColons => format!( + "\"{}\" contains multiple standalone ':' separators", + display_name + ), + Self::EmptyColonSuffix => { + format!( + "\"{}\" uses ':' without a non-empty right-hand side", + display_name + ) + } + } + } +} + +fn unsupported_participant_display_form( + participant_info: &SequenceParticipantInfo, +) -> Option { + let primary_line = first_nonempty_display_line(&participant_info.display_name)?; + let separator_colons = separator_colon_positions(primary_line); + + if separator_colons.len() > 1 { + return Some(UnsupportedParticipantDisplayForm::MultipleStandaloneColons); + } + + if let Some(colon_index) = separator_colons.first() { + if primary_line[colon_index + 1..].trim().is_empty() { + return Some(UnsupportedParticipantDisplayForm::EmptyColonSuffix); + } + } + + None +} + +fn class_match_candidates_from_display( + participant_info: &SequenceParticipantInfo, +) -> ClassMatchCandidates { + let Some(primary_line) = first_nonempty_display_line(&participant_info.display_name) else { + return ClassMatchCandidates::default(); + }; + + let separator_colons = separator_colon_positions(primary_line); + if separator_colons.len() != 1 { + return ClassMatchCandidates::default(); + } + + let colon_index = separator_colons[0]; + if colon_index == 0 { + let short_name = primary_line[1..].trim(); + if short_name.is_empty() { + return ClassMatchCandidates::default(); + } + + return ClassMatchCandidates { + id_candidates: Vec::new(), + name_candidates: vec![short_name.to_string()], + }; + } + + let Some(type_text) = text_after_separator_colon(primary_line, colon_index) else { + return ClassMatchCandidates::default(); + }; + + class_match_candidates_from_type_text(type_text) +} + +fn participant_suggestion_queries( + participant: &str, + participant_info: &SequenceParticipantInfo, +) -> Vec { + let mut queries = BTreeSet::new(); + + insert_participant_suggestion_query(&mut queries, participant); + + if participant_info.display_name != participant { + insert_participant_suggestion_query(&mut queries, &participant_info.display_name); + } + + let display_candidates = class_match_candidates_from_display(participant_info); + for candidate in display_candidates + .id_candidates + .into_iter() + .chain(display_candidates.name_candidates) + { + insert_participant_suggestion_query(&mut queries, &candidate); + } + + queries.into_iter().collect() +} + +fn insert_participant_suggestion_query(queries: &mut BTreeSet, query: &str) { + if query.is_empty() { + return; + } + + queries.insert(query.to_string()); + + let normalized_query = SequenceParticipantInfo::normalize_qualified_name(query); + if normalized_query != query { + queries.insert(normalized_query); + } +} + +fn text_after_separator_colon(primary_line: &str, colon_index: usize) -> Option<&str> { + let type_text = primary_line[colon_index + 1..].trim(); + (!type_text.is_empty()).then_some(type_text) +} + +fn class_match_candidates_from_type_text(type_text: &str) -> ClassMatchCandidates { + let mut candidates = ClassMatchCandidates { + id_candidates: Vec::new(), + name_candidates: Vec::new(), + }; + + if type_text.contains("::") { + candidates.id_candidates.push(type_text.to_string()); + } + + candidates.name_candidates.push(type_text.to_string()); + + if let Some(short_name) = type_text.rsplit("::").next().map(str::trim) { + if !short_name.is_empty() && short_name != type_text { + candidates.name_candidates.push(short_name.to_string()); + } + } + + candidates +} + +fn ignored_special_display_suffix(participant_info: &SequenceParticipantInfo) -> Option { + let normalized_segments = normalized_display_segments(&participant_info.display_name); + let (primary_line, ignored_segments) = normalized_segments.split_first()?; + let separator_colons = separator_colon_positions(primary_line); + + if separator_colons.len() != 1 || ignored_segments.is_empty() { + return None; + } + + Some(ignored_segments.join(" | ")) +} + +fn first_nonempty_display_line(display_name: &str) -> Option<&str> { + normalized_display_segments(display_name).into_iter().next() +} + +fn normalized_display_segments(display_name: &str) -> Vec<&str> { + let mut lines = Vec::new(); + + for physical_line in display_name.lines() { + for escaped_line in physical_line + .split("\\n") + .flat_map(|segment| segment.split("/n")) + { + let trimmed = escaped_line.trim(); + if !trimmed.is_empty() { + lines.push(trimmed); + } + } + } + + lines +} + +fn separator_colon_positions(text: &str) -> Vec { + const COLON: u8 = b':'; + + let bytes = text.as_bytes(); + + bytes + .iter() + .enumerate() + .filter_map(|(index, byte)| { + if *byte != COLON { + return None; + } + + let previous_is_colon = index > 0 && bytes[index - 1] == COLON; + let next_is_colon = index + 1 < bytes.len() && bytes[index + 1] == COLON; + + (!previous_is_colon && !next_is_colon).then_some(index) + }) + .collect() +} + +fn format_name_set(names: &BTreeSet) -> String { + names + .iter() + .map(|name| format!("\"{name}\"")) + .collect::>() + .join(", ") +} + +fn append_debug_log( + diagnostics: &mut Diagnostics, + design_classes: &ClassEntityIndex, + sequence_diagram: &SequenceDiagramIndex, +) { + diagnostics.debug(|| "Design classes available for sequence validation:".to_string()); + for entity in design_classes.entities() { + diagnostics.debug(|| format!(" {}", entity.id)); + } + + diagnostics.debug(|| "Observed participants from sequence diagrams:".to_string()); + for participant in sequence_diagram.declared_participants() { + diagnostics.debug(|| format!(" {participant}")); + } + + diagnostics.debug(|| "Observed sequence calls from sequence diagrams:".to_string()); + for observed_call in sequence_diagram.observed_calls() { + diagnostics.debug(|| { + format!( + " {} -> {} : {}", + observed_call.caller, observed_call.callee, observed_call.method + ) + }); + } +} + +#[cfg(test)] +#[path = "test/class_design_sequence_validator_test.rs"] +mod tests; diff --git a/validation/core/src/validators/component_sequence_validator.rs b/validation/core/src/validators/component_sequence_validator.rs index a5cc8a37..1c2c66af 100644 --- a/validation/core/src/validators/component_sequence_validator.rs +++ b/validation/core/src/validators/component_sequence_validator.rs @@ -16,13 +16,14 @@ use std::collections::{BTreeMap, BTreeSet}; -use sequence_logic::SourceLocation; - use super::shared::{ best_string_suggestion, build_observed_call_contexts, build_unit_bindings, format_name_list, intersect_interfaces, SequenceCallContext, UnitBindings, }; -use crate::models::{is_external_endpoint, ComponentDiagramArchitecture, SequenceDiagramIndex}; +use crate::models::{ + is_external_endpoint, ComponentDiagramArchitecture, SequenceDiagramIndex, + SequenceParticipantInfo, +}; use crate::results::{ErrorBuilder, ErrorCategory}; use crate::{Diagnostics, ValidationResult}; @@ -37,7 +38,7 @@ pub fn validate_component_sequence( type ConnectedUnitPairs = BTreeMap<(String, String), BTreeSet>; struct ComponentSequenceValidator<'a> { - participants: &'a BTreeMap, + participants: &'a BTreeMap, observed_call_contexts: Vec>, connected_unit_pairs: ConnectedUnitPairs, unit_bindings: UnitBindings, @@ -158,7 +159,8 @@ impl<'a> ComponentSequenceValidator<'a> { for participant in self.participants.keys().filter(|participant| { !is_external_endpoint(participant) && !self.unit_bindings.contains_key(*participant) }) { - let (source_file, source_line) = self.participants[participant].display(); + let (source_file, source_line) = + self.participants[participant].source_location.display(); let error = ErrorBuilder::new(ErrorCategory::Naming) .title(format!( diff --git a/validation/core/src/validators/mod.rs b/validation/core/src/validators/mod.rs index 190482fc..ba23d7ad 100644 --- a/validation/core/src/validators/mod.rs +++ b/validation/core/src/validators/mod.rs @@ -15,6 +15,7 @@ mod bazel_component_validator; mod class_design_implementation_validator; +mod class_design_sequence_validator; mod component_internal_api_validator; mod component_public_api_validator; mod component_sequence_validator; @@ -27,6 +28,7 @@ pub(crate) mod fixtures; pub use bazel_component_validator::validate_bazel_component; pub use class_design_implementation_validator::validate_class_design_implementation; +pub use class_design_sequence_validator::validate_class_design_sequence; pub use component_internal_api_validator::validate_component_internal_api; pub use component_public_api_validator::validate_component_public_api; pub use component_sequence_validator::validate_component_sequence; diff --git a/validation/core/src/validators/test/class_design_sequence_validator_test.rs b/validation/core/src/validators/test/class_design_sequence_validator_test.rs new file mode 100644 index 00000000..a85cbfca --- /dev/null +++ b/validation/core/src/validators/test/class_design_sequence_validator_test.rs @@ -0,0 +1,227 @@ +// ******************************************************************************* +// Copyright (c) 2026 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License Version 2.0 which is available at +// +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +use super::super::fixtures::*; +use super::*; +use crate::models::{ClassDiagramInputs, ClassEntityIndex, SequenceDiagramInputs}; +use crate::ValidationResult; +use class_diagram::{ClassDiagram, RelationType, Relationship}; + +fn validate( + design_classes: ClassDiagramInputs, + sequence_diagrams: SequenceDiagramInputs, +) -> ValidationResult { + let mut setup_result = ValidationResult::default(); + let design_index = ClassEntityIndex::build_index(&design_classes, &mut setup_result); + let sequence_index = sequence_diagrams.to_sequence_diagram_index(&mut setup_result); + assert!( + setup_result.is_empty(), + "test fixture setup failed: {:?}", + setup_result.failures + ); + + validate_class_design_sequence(&design_index, &sequence_index) +} + +fn class_diagrams(entities: Vec) -> ClassDiagramInputs { + vec![ClassDiagram { + name: "class_design".to_string(), + entities, + }] +} + +fn class_entity(id: &str, namespace: Option<&str>) -> class_diagram::SimpleEntity { + let mut entity = class_interface(id, namespace); + entity.entity_type = class_diagram::EntityType::Class; + entity +} + +#[test] +fn passes_when_all_sequence_participants_match_design_classes() { + let design_classes = class_diagrams(vec![ + class_entity("Controller", None), + class_entity("Repository", None), + ]); + let sequence_diagrams = sequence_diagrams(&["Controller", "Repository"]); + + let validation_result = validate(design_classes, sequence_diagrams); + + assert!(validation_result.failures.is_empty()); +} + +#[test] +fn reports_sequence_participant_missing_from_design_classes() { + let design_classes = class_diagrams(vec![class_entity("Controller", None)]); + let sequence_diagrams = sequence_calls(&[("Controller", "Repository", "FindById()")]); + + let validation_result = validate(design_classes, sequence_diagrams); + + assert_eq!(validation_result.failures.len(), 1); + assert!(validation_result.failures[0].contains( + "[Class] Sequence participant \"Repository\" has no matching class in the class diagram." + )); + assert!(validation_result.failures[0].contains("\"Repository\"")); +} + +#[test] +fn reports_sequence_participant_missing_with_fuzzy_class_suggestion() { + let design_classes = class_diagrams(vec![class_entity("Repository", None)]); + let sequence_diagrams = sequence_diagrams(&["Repositry"]); + + let validation_result = validate(design_classes, sequence_diagrams); + + assert_eq!(validation_result.failures.len(), 1); + assert!(validation_result.failures[0] + .contains("Suggestion for \"Repositry\" : Did you mean class \"Repository\"?")); +} + +#[test] +fn matches_sequence_participant_against_fully_qualified_class_id() { + let design_classes = class_diagrams(vec![class_entity("Controller", Some("unit_1"))]); + let sequence_diagrams = sequence_diagrams(&["unit_1::Controller"]); + + let validation_result = validate(design_classes, sequence_diagrams); + + assert!(validation_result.failures.is_empty()); +} + +#[test] +fn matches_sequence_participant_against_unique_short_name() { + let design_classes = class_diagrams(vec![class_entity("Controller", Some("unit_1"))]); + let sequence_diagrams = sequence_diagrams(&["Controller"]); + + let validation_result = validate(design_classes, sequence_diagrams); + + assert!(validation_result.failures.is_empty()); +} + +#[test] +fn reports_sequence_participant_with_ambiguous_short_name() { + let design_classes = class_diagrams(vec![ + class_entity("Controller", Some("unit_1")), + class_entity("Controller", Some("unit_2")), + ]); + let sequence_diagrams = sequence_diagrams(&["Controller"]); + + let validation_result = validate(design_classes, sequence_diagrams); + + assert_eq!(validation_result.failures.len(), 1); + assert!(validation_result.failures[0].contains( + "[Class] Sequence participant \"Controller\" matches multiple classes in the class diagram." + )); + assert!(validation_result.failures[0].contains("\"unit_1.Controller\"")); + assert!(validation_result.failures[0].contains("\"unit_2.Controller\"")); +} + +#[test] +fn passes_when_sequence_call_targets_existing_method_on_callee_class() { + let mut repository = class_entity("Repository", None); + repository.methods = vec![method("FindById")]; + + let design_classes = class_diagrams(vec![class_entity("Controller", None), repository]); + let sequence_diagrams = sequence_calls(&[("Controller", "Repository", "FindById()")]); + + let validation_result = validate(design_classes, sequence_diagrams); + + assert!(validation_result.failures.is_empty()); +} + +#[test] +fn reports_sequence_call_method_missing_from_callee_class() { + let mut repository = class_entity("Repository", None); + repository.methods = vec![method("Store")]; + + let design_classes = class_diagrams(vec![class_entity("Controller", None), repository]); + let sequence_diagrams = sequence_calls(&[("Controller", "Repository", "FindById()")]); + + let validation_result = validate(design_classes, sequence_diagrams); + + assert_eq!(validation_result.failures.len(), 1); + assert!(validation_result.failures[0].contains( + "[Method] Sequence function \"FindById\" from sequence call \"Controller\" -> \"Repository\" : \"FindById\" not found on target class \"Repository\" or its accessible inherited types in the class diagram." + )); + assert!(validation_result.failures[0].contains("\"Repository\"")); +} + +#[test] +fn reports_sequence_call_method_missing_with_inherited_fuzzy_suggestion() { + let mut repository_base = class_entity("RepositoryBase", None); + repository_base.methods = vec![method("FindById")]; + + let mut repository = class_entity("Repository", None); + repository.relationships = vec![relationship( + "Repository", + "RepositoryBase", + RelationType::Inheritance, + )]; + + let design_classes = class_diagrams(vec![ + class_entity("Controller", None), + repository, + repository_base, + ]); + let sequence_diagrams = sequence_calls(&[("Controller", "Repository", "FindByIds()")]); + + let validation_result = validate(design_classes, sequence_diagrams); + + assert_eq!(validation_result.failures.len(), 1); + assert!(validation_result.failures[0] + .contains("Suggestion for \"FindByIds\" : Did you mean method \"FindById\"?")); +} + +#[test] +fn passes_when_sequence_self_call_targets_existing_method() { + let mut controller = class_entity("Controller", None); + controller.methods = vec![method("Validate")]; + + let design_classes = class_diagrams(vec![controller]); + let sequence_diagrams = sequence_calls(&[("Controller", "Controller", "Validate()")]); + + let validation_result = validate(design_classes, sequence_diagrams); + + assert!(validation_result.failures.is_empty()); +} + +#[test] +fn extracts_ignored_special_display_suffix() { + let mut sequence_diagrams = sequence_diagrams(&["help"]); + sequence_diagrams.diagrams[0].participants[0].display_name = + ":Process/nara::com user".to_string(); + sequence_diagrams.diagrams[0].participants[0].alias = Some("help".to_string()); + + let mut setup_result = ValidationResult::default(); + let sequence_index = sequence_diagrams.to_sequence_diagram_index(&mut setup_result); + assert!( + setup_result.is_empty(), + "test fixture setup failed: {:?}", + setup_result.failures + ); + + let participant_info = sequence_index.participant_info("help").unwrap(); + + assert_eq!( + ignored_special_display_suffix(participant_info), + Some("ara::com user".to_string()) + ); +} + +fn relationship(source: &str, target: &str, relation_type: RelationType) -> Relationship { + Relationship { + source: source.to_string(), + target: target.to_string(), + relation_type, + source_multiplicity: None, + target_multiplicity: None, + source_location: dummy_source_location(), + } +} diff --git a/validation/core/src/validators/test/fixtures.rs b/validation/core/src/validators/test/fixtures.rs index d7ef5145..15f35966 100644 --- a/validation/core/src/validators/test/fixtures.rs +++ b/validation/core/src/validators/test/fixtures.rs @@ -213,7 +213,7 @@ fn simple_entity(name: &str, entity_type: EntityType, namespace: Option<&str>) - } } -fn method(name: &str) -> Method { +pub(super) fn method(name: &str) -> Method { Method { name: name.to_string(), return_type: None,