diff --git a/MODULE.bazel b/MODULE.bazel index 211b3ca2..a5282d82 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -133,6 +133,10 @@ crate.spec( package = "serde_yaml", version = "0.9", ) +crate.spec( + package = "strsim", + version = "0.11", +) crate.spec( package = "once_cell", version = "1.19", diff --git a/validation/core/BUILD b/validation/core/BUILD index 78ee2a3c..2edf1253 100644 --- a/validation/core/BUILD +++ b/validation/core/BUILD @@ -87,6 +87,7 @@ rust_library( "@crates//:log", "@crates//:serde", "@crates//:serde_json", + "@crates//:strsim", ], ) diff --git a/validation/core/integration_test/bazel_component/negative_extra_unit/expected.yaml b/validation/core/integration_test/bazel_component/negative_extra_unit/expected.yaml index 2cdc25f6..f76127a0 100644 --- a/validation/core/integration_test/bazel_component/negative_extra_unit/expected.yaml +++ b/validation/core/integration_test/bazel_component/negative_extra_unit/expected.yaml @@ -13,8 +13,9 @@ should_pass: false error_contains: | [Naming] Unit "unit_3" from the PlantUML component diagram not found in Bazel. - Alias : "unit_3" - Parent : component_example - Component source file : "validation/core/integration_test/bazel_component/negative_extra_unit/component_diagram.puml" - Component source line : 20 - Fix : Add the corresponding Bazel unit definition for "unit_3", or remove it from the PlantUML component diagram. + Alias : "unit_3" + Parent : component_example + Component source file : "validation/core/integration_test/bazel_component/negative_extra_unit/component_diagram.puml" + Component source line : 20 + Suggestion for "unit_3" : Did you mean unit "unit_1"? + Fix : Add the corresponding Bazel unit definition for "unit_3", or remove it from the PlantUML component diagram. diff --git a/validation/core/integration_test/bazel_component/negative_missing_unit/expected.yaml b/validation/core/integration_test/bazel_component/negative_missing_unit/expected.yaml index a46e3019..fa98b642 100644 --- a/validation/core/integration_test/bazel_component/negative_missing_unit/expected.yaml +++ b/validation/core/integration_test/bazel_component/negative_missing_unit/expected.yaml @@ -13,8 +13,9 @@ should_pass: false error_contains: | [Naming] Unit "unit_2" from Bazel not found in the PlantUML component diagram. - Alias : "unit_2" - Parent : component_example - Stereotype : <> - Bazel label : @//bazel/rules/rules_score/examples/seooc/unit_2:unit_2 - Fix : Add unit "unit_2" with stereotype <> in the PlantUML component diagram, or remove it from Bazel. + Alias : "unit_2" + Parent : component_example + Stereotype : <> + Bazel label : @//bazel/rules/rules_score/examples/seooc/unit_2:unit_2 + Suggestion for "unit_2" : Did you mean unit "unit_1"? + Fix : Add unit "unit_2" with stereotype <> in the PlantUML component diagram, or remove it from Bazel. diff --git a/validation/core/integration_test/class_design_implementation/BUILD b/validation/core/integration_test/class_design_implementation/BUILD index c6052d0b..1fdb6df4 100644 --- a/validation/core/integration_test/class_design_implementation/BUILD +++ b/validation/core/integration_test/class_design_implementation/BUILD @@ -17,13 +17,17 @@ filegroup( name = "class_design_implementation_test_data", srcs = [ "//validation/core/integration_test/class_design_implementation/negative_class_member_missing:case_data", + "//validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion:case_data", + "//validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion:case_data", "//validation/core/integration_test/class_design_implementation/negative_duplicate_class_entity_input:case_data", "//validation/core/integration_test/class_design_implementation/negative_class_missing:case_data", "//validation/core/integration_test/class_design_implementation/negative_entity_type_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_enum_literal_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_enum_literal_missing:case_data", + "//validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion:case_data", "//validation/core/integration_test/class_design_implementation/negative_method_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_method_modifier_mismatch:case_data", + "//validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion:case_data", "//validation/core/integration_test/class_design_implementation/negative_method_parameter_count_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_method_parameter_name_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_method_parameter_type_mismatch:case_data", @@ -31,11 +35,14 @@ filegroup( "//validation/core/integration_test/class_design_implementation/negative_method_visibility_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_method_missing:case_data", "//validation/core/integration_test/class_design_implementation/negative_relationship_missing:case_data", + "//validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion:case_data", "//validation/core/integration_test/class_design_implementation/negative_relationship_type_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_template_parameter_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_template_parameter_pack_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_type_alias_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_type_alias_missing:case_data", + "//validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion:case_data", + "//validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion:case_data", "//validation/core/integration_test/class_design_implementation/negative_variable_static_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_variable_visibility_mismatch:case_data", "//validation/core/integration_test/class_design_implementation/negative_variable_mismatch:case_data", diff --git a/validation/core/integration_test/class_design_implementation/class_design_implementation_suite.rs b/validation/core/integration_test/class_design_implementation/class_design_implementation_suite.rs index f82bf716..33bbca64 100644 --- a/validation/core/integration_test/class_design_implementation/class_design_implementation_suite.rs +++ b/validation/core/integration_test/class_design_implementation/class_design_implementation_suite.rs @@ -92,6 +92,41 @@ fn negative_class_member_missing() { assert_case("negative_class_member_missing"); } +#[test] +fn negative_class_missing_with_suggestion() { + assert_case("negative_class_missing_with_suggestion"); +} + +#[test] +fn negative_class_missing_without_suggestion() { + assert_case("negative_class_missing_without_suggestion"); +} + +#[test] +fn negative_type_alias_missing_with_suggestion() { + assert_case("negative_type_alias_missing_with_suggestion"); +} + +#[test] +fn negative_variable_missing_with_suggestion() { + assert_case("negative_variable_missing_with_suggestion"); +} + +#[test] +fn negative_method_missing_with_suggestion() { + assert_case("negative_method_missing_with_suggestion"); +} + +#[test] +fn negative_enum_literal_missing_with_suggestion() { + assert_case("negative_enum_literal_missing_with_suggestion"); +} + +#[test] +fn negative_relationship_missing_with_suggestion() { + assert_case("negative_relationship_missing_with_suggestion"); +} + #[test] fn negative_duplicate_class_entity_input() { assert_case("negative_duplicate_class_entity_input"); diff --git a/validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/BUILD b/validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/BUILD new file mode 100644 index 00000000..c3206a03 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/BUILD @@ -0,0 +1,54 @@ +# ******************************************************************************* +# 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", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +cc_library( + name = "transport", + srcs = ["transport.cpp"], +) + +unit( + name = "unit", + testonly = False, + maturity = "development", + tests = [], + unit_design = [":unit_design"], + visibility = ["//visibility:private"], + implementation = [":transport"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [ + ":unit", + ":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_implementation/negative_class_missing_with_suggestion/class_diagram.puml b/validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/class_diagram.puml new file mode 100644 index 00000000..d0bb9700 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/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 ControlPanel + +@enduml diff --git a/validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/expected.yaml b/validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/expected.yaml new file mode 100644 index 00000000..ba16d0f6 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_class_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] Class "ControlPanel" from the unit design not found in the C++ class implementation. + Class : "ControlPanel" + Design source file : "validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/class_diagram.puml" + Design source line : 16 + Suggestion for "ControlPanel" : Did you mean class "ControlPanl"? + Fix : Add implementation class "ControlPanel" in the C++ class implementation, or remove it from the unit design. diff --git a/validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/transport.cpp b/validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/transport.cpp new file mode 100644 index 00000000..8624c837 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_class_missing_with_suggestion/transport.cpp @@ -0,0 +1,16 @@ +/******************************************************************************** + * 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 + ********************************************************************************/ + +class ControlPanl +{ +}; diff --git a/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/BUILD b/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/BUILD new file mode 100644 index 00000000..c3206a03 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/BUILD @@ -0,0 +1,54 @@ +# ******************************************************************************* +# 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", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +cc_library( + name = "transport", + srcs = ["transport.cpp"], +) + +unit( + name = "unit", + testonly = False, + maturity = "development", + tests = [], + unit_design = [":unit_design"], + visibility = ["//visibility:private"], + implementation = [":transport"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [ + ":unit", + ":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_implementation/negative_class_missing_without_suggestion/class_diagram.puml b/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/class_diagram.puml new file mode 100644 index 00000000..c6c7f7a9 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/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 TelemetryBroker + +@enduml diff --git a/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/expected.yaml b/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/expected.yaml new file mode 100644 index 00000000..751b2430 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/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] Class "TelemetryBroker" from the unit design not found in the C++ class implementation. + Class : "TelemetryBroker" + Design source file : "validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/class_diagram.puml" + Design source line : 16 + Fix : Add implementation class "TelemetryBroker" in the C++ class implementation, or remove it from the unit design. diff --git a/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/transport.cpp b/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/transport.cpp new file mode 100644 index 00000000..e76a155f --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_class_missing_without_suggestion/transport.cpp @@ -0,0 +1,24 @@ +/******************************************************************************** + * 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 + ********************************************************************************/ + +class Engine +{ +}; + +class Wheel +{ +}; + +class Dashboard +{ +}; diff --git a/validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion/BUILD b/validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion/BUILD new file mode 100644 index 00000000..c3206a03 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion/BUILD @@ -0,0 +1,54 @@ +# ******************************************************************************* +# 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", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +cc_library( + name = "transport", + srcs = ["transport.cpp"], +) + +unit( + name = "unit", + testonly = False, + maturity = "development", + tests = [], + unit_design = [":unit_design"], + visibility = ["//visibility:private"], + implementation = [":transport"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [ + ":unit", + ":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_implementation/negative_enum_literal_missing_with_suggestion/class_diagram.puml b/validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion/class_diagram.puml new file mode 100644 index 00000000..e3e55648 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_enum_literal_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 + +enum Mode { + ActiveState +} + +@enduml diff --git a/validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion/expected.yaml b/validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion/expected.yaml new file mode 100644 index 00000000..9c46a12e --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_enum_literal_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: |- + [Member] Enum_literal "ActiveState" from entity "Mode" in the unit design not found in the C++ class implementation. + Entity : "Mode" + Member : enum_literal "ActiveState" + Design source file : "validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion/class_diagram.puml" + Design source line : 16 + Suggestion for "ActiveState" : Did you mean enum_literal "ActiveStat"? + Fix : Add enum_literal "ActiveState" to entity "Mode" in the C++ class implementation, or remove it from the unit design. diff --git a/validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion/transport.cpp b/validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion/transport.cpp new file mode 100644 index 00000000..9eb70902 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_enum_literal_missing_with_suggestion/transport.cpp @@ -0,0 +1,17 @@ +/******************************************************************************** + * 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 + ********************************************************************************/ + +enum class Mode +{ + ActiveStat +}; diff --git a/validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion/BUILD b/validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion/BUILD new file mode 100644 index 00000000..c3206a03 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion/BUILD @@ -0,0 +1,54 @@ +# ******************************************************************************* +# 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", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +cc_library( + name = "transport", + srcs = ["transport.cpp"], +) + +unit( + name = "unit", + testonly = False, + maturity = "development", + tests = [], + unit_design = [":unit_design"], + visibility = ["//visibility:private"], + implementation = [":transport"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [ + ":unit", + ":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_implementation/negative_method_missing_with_suggestion/class_diagram.puml b/validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion/class_diagram.puml new file mode 100644 index 00000000..cf9cfb5f --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_method_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 Engine { + + run() : void +} + +@enduml diff --git a/validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion/expected.yaml b/validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion/expected.yaml new file mode 100644 index 00000000..6a3404bd --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_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: |- + [Member] Method "run()" from entity "Engine" in the unit design not found in the C++ class implementation. + Entity : "Engine" + Member : method "run()" + Design source file : "validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion/class_diagram.puml" + Design source line : 16 + Suggestion for "run()" : Did you mean method "rn()"? + Fix : Add method "run()" to entity "Engine" in the C++ class implementation, or remove it from the unit design. diff --git a/validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion/transport.cpp b/validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion/transport.cpp new file mode 100644 index 00000000..72ec9889 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_method_missing_with_suggestion/transport.cpp @@ -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 + ********************************************************************************/ + +class Engine +{ + public: + void rn(); +}; diff --git a/validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/BUILD b/validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/BUILD new file mode 100644 index 00000000..c3206a03 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/BUILD @@ -0,0 +1,54 @@ +# ******************************************************************************* +# 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", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +cc_library( + name = "transport", + srcs = ["transport.cpp"], +) + +unit( + name = "unit", + testonly = False, + maturity = "development", + tests = [], + unit_design = [":unit_design"], + visibility = ["//visibility:private"], + implementation = [":transport"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [ + ":unit", + ":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_implementation/negative_relationship_missing_with_suggestion/class_diagram.puml b/validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/class_diagram.puml new file mode 100644 index 00000000..31890908 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/class_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 + +struct Wheel +struct Car + +Wheel *-- Car + +@enduml diff --git a/validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/expected.yaml b/validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/expected.yaml new file mode 100644 index 00000000..ab198e5d --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_relationship_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: |- + [Member] Relationship "Car -> Composition -> Wheel" from entity "Car" in the unit design not found in the C++ class implementation. + Entity : "Car" + Member : relationship "Car -> Composition -> Wheel" + Design source file : "validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/class_diagram.puml" + Design source line : 17 + Suggestion for "Car -> Composition -> Wheel" : Did you mean relationship "Car -> Composition -> Whell"? + Fix : Add relationship "Car -> Composition -> Wheel" to entity "Car" in the C++ class implementation, or remove it from the unit design. diff --git a/validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/transport.cpp b/validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/transport.cpp new file mode 100644 index 00000000..99a9b1eb --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_relationship_missing_with_suggestion/transport.cpp @@ -0,0 +1,25 @@ +/******************************************************************************** + * 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 + ********************************************************************************/ + +struct Whell +{ +}; + +struct Wheel +{ +}; + +struct Car +{ + Whell whell; +}; diff --git a/validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion/BUILD b/validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion/BUILD new file mode 100644 index 00000000..c3206a03 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion/BUILD @@ -0,0 +1,54 @@ +# ******************************************************************************* +# 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", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +cc_library( + name = "transport", + srcs = ["transport.cpp"], +) + +unit( + name = "unit", + testonly = False, + maturity = "development", + tests = [], + unit_design = [":unit_design"], + visibility = ["//visibility:private"], + implementation = [":transport"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [ + ":unit", + ":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_implementation/negative_type_alias_missing_with_suggestion/class_diagram.puml b/validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion/class_diagram.puml new file mode 100644 index 00000000..a03b3be7 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_type_alias_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 Engine { + using SpeedAlias = std::uint8_t; +} + +@enduml diff --git a/validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion/expected.yaml b/validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion/expected.yaml new file mode 100644 index 00000000..7fa794bf --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_type_alias_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: |- + [Member] Type_alias "SpeedAlias" from entity "Engine" in the unit design not found in the C++ class implementation. + Entity : "Engine" + Member : type_alias "SpeedAlias" + Design source file : "validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion/class_diagram.puml" + Design source line : 16 + Suggestion for "SpeedAlias" : Did you mean type_alias "SpeedAlia"? + Fix : Add type_alias "SpeedAlias" to entity "Engine" in the C++ class implementation, or remove it from the unit design. diff --git a/validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion/transport.cpp b/validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion/transport.cpp new file mode 100644 index 00000000..7fc89734 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_type_alias_missing_with_suggestion/transport.cpp @@ -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 + ********************************************************************************/ + +#include + +class Engine +{ + using SpeedAlia = std::uint8_t; +}; diff --git a/validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion/BUILD b/validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion/BUILD new file mode 100644 index 00000000..c3206a03 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion/BUILD @@ -0,0 +1,54 @@ +# ******************************************************************************* +# 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", "unit_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +unit_design( + name = "unit_design", + static = ["class_diagram.puml"], + visibility = ["//visibility:private"], +) + +cc_library( + name = "transport", + srcs = ["transport.cpp"], +) + +unit( + name = "unit", + testonly = False, + maturity = "development", + tests = [], + unit_design = [":unit_design"], + visibility = ["//visibility:private"], + implementation = [":transport"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [ + ":unit", + ":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_implementation/negative_variable_missing_with_suggestion/class_diagram.puml b/validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion/class_diagram.puml new file mode 100644 index 00000000..ccd9506c --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_variable_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 + +struct Engine { + + value_count : int +} + +@enduml diff --git a/validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion/expected.yaml b/validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion/expected.yaml new file mode 100644 index 00000000..339615a4 --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_variable_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: |- + [Member] Variable "value_count" from entity "Engine" in the unit design not found in the C++ class implementation. + Entity : "Engine" + Member : variable "value_count" + Design source file : "validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion/class_diagram.puml" + Design source line : 16 + Suggestion for "value_count" : Did you mean variable "valuecount"? + Fix : Add variable "value_count" to entity "Engine" in the C++ class implementation, or remove it from the unit design. diff --git a/validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion/transport.cpp b/validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion/transport.cpp new file mode 100644 index 00000000..9668720f --- /dev/null +++ b/validation/core/integration_test/class_design_implementation/negative_variable_missing_with_suggestion/transport.cpp @@ -0,0 +1,17 @@ +/******************************************************************************** + * 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 + ********************************************************************************/ + +struct Engine +{ + int valuecount; +}; diff --git a/validation/core/integration_test/component_internal_api/BUILD b/validation/core/integration_test/component_internal_api/BUILD index f9521319..8d1d86e1 100644 --- a/validation/core/integration_test/component_internal_api/BUILD +++ b/validation/core/integration_test/component_internal_api/BUILD @@ -21,6 +21,8 @@ filegroup( "//validation/core/integration_test/component_internal_api/negative_duplicate_interface_alias_casefolded:case_data", "//validation/core/integration_test/component_internal_api/negative_duplicate_unit_alias_casefolded:case_data", "//validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api:case_data", + "//validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion:case_data", + "//validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions:case_data", "//validation/core/integration_test/component_internal_api/positive_interface_match:case_data", ], ) diff --git a/validation/core/integration_test/component_internal_api/component_internal_api_suite.rs b/validation/core/integration_test/component_internal_api/component_internal_api_suite.rs index cec6b424..73423330 100644 --- a/validation/core/integration_test/component_internal_api/component_internal_api_suite.rs +++ b/validation/core/integration_test/component_internal_api/component_internal_api_suite.rs @@ -56,6 +56,16 @@ fn negative_interface_missing_from_internal_api_suite_case() { assert_case("negative_interface_missing_from_internal_api"); } +#[test] +fn negative_interface_missing_from_internal_api_with_suggestion_suite_case() { + assert_case("negative_interface_missing_from_internal_api_with_suggestion"); +} + +#[test] +fn negative_interfaces_missing_from_internal_api_with_suggestions_suite_case() { + assert_case("negative_interfaces_missing_from_internal_api_with_suggestions"); +} + #[test] fn negative_duplicate_unit_alias_casefolded_suite_case() { assert_case("negative_duplicate_unit_alias_casefolded"); diff --git a/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/BUILD b/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/BUILD new file mode 100644 index 00000000..26b6054f --- /dev/null +++ b/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/BUILD @@ -0,0 +1,38 @@ +# ******************************************************************************* +# 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", "architectural_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +architectural_design( + name = "design", + internal_api = ["internal_api_diagram.puml"], + maturity = "development", + static = ["component_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:public"], + deps = [":design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//visibility:public"], +) diff --git a/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/component_diagram.puml b/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/component_diagram.puml new file mode 100644 index 00000000..c87543a4 --- /dev/null +++ b/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/component_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 component_diagram + +package "Package A" as package_a { + component "Component A" as component_a <> { + component "Unit 1" as unit_1 <> + component "Unit 2" as unit_2 <> + } + + interface "InternalInterface" as InternalInterface + unit_1 -( InternalInterface + unit_2 )- InternalInterface +} + +@enduml diff --git a/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/expected.yaml b/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/expected.yaml new file mode 100644 index 00000000..a95bf27e --- /dev/null +++ b/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_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: |- + [Interface] Component interface(s) "package_a.InternalInterface" from the component diagram not found in the internal API diagram. + Missing interfaces : "package_a.InternalInterface" + Component source file for "package_a.InternalInterface" : "validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/component_diagram.puml" + Component source line for "package_a.InternalInterface" : 22 + Suggestion for "package_a.InternalInterface" : Did you mean interface "package_a.internal_interface"? + Fix : Add interface declaration(s) "package_a.InternalInterface" in the internal API diagram, or remove those interface declarations from the component diagram. diff --git a/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/internal_api_diagram.puml b/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/internal_api_diagram.puml new file mode 100644 index 00000000..5a9f457d --- /dev/null +++ b/validation/core/integration_test/component_internal_api/negative_interface_missing_from_internal_api_with_suggestion/internal_api_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 + +package package_a { + interface "internal_interface" as internal_interface { + + GetData() + } +} + +@enduml diff --git a/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/BUILD b/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/BUILD new file mode 100644 index 00000000..f3a99992 --- /dev/null +++ b/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/BUILD @@ -0,0 +1,38 @@ +# ******************************************************************************* +# 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", "architectural_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +architectural_design( + name = "design", + internal_api = ["internal_api_diagram.puml"], + maturity = "development", + static = ["component_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/component_diagram.puml b/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/component_diagram.puml new file mode 100644 index 00000000..af8da73e --- /dev/null +++ b/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/component_diagram.puml @@ -0,0 +1,30 @@ +' ******************************************************************************* +' 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 component_diagram + +package "Package A" as package_a { + component "Component A" as component_a <> { + component "Unit 1" as unit_1 <> + component "Unit 2" as unit_2 <> + } + + interface "DiagnosticsInterface" as DiagnosticsInterface + interface "InternalInterface" as InternalInterface + unit_1 -( DiagnosticsInterface + unit_1 -( InternalInterface + unit_2 )- DiagnosticsInterface + unit_2 )- InternalInterface +} + +@enduml diff --git a/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/expected.yaml b/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/expected.yaml new file mode 100644 index 00000000..03bca386 --- /dev/null +++ b/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/expected.yaml @@ -0,0 +1,23 @@ +# ******************************************************************************* +# 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: |- + [Interface] Component interface(s) "package_a.DiagnosticsInterface", "package_a.InternalInterface" from the component diagram not found in the internal API diagram. + Missing interfaces : "package_a.DiagnosticsInterface", "package_a.InternalInterface" + Component source file for "package_a.DiagnosticsInterface" : "validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/component_diagram.puml" + Component source line for "package_a.DiagnosticsInterface" : 22 + Suggestion for "package_a.DiagnosticsInterface" : Did you mean interface "package_a.diagnostics_interfac"? + Component source file for "package_a.InternalInterface" : "validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/component_diagram.puml" + Component source line for "package_a.InternalInterface" : 23 + Suggestion for "package_a.InternalInterface" : Did you mean interface "package_a.internal_interface"? + Fix : Add interface declaration(s) "package_a.DiagnosticsInterface", "package_a.InternalInterface" in the internal API diagram, or remove those interface declarations from the component diagram. diff --git a/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/internal_api_diagram.puml b/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/internal_api_diagram.puml new file mode 100644 index 00000000..9ea9ab86 --- /dev/null +++ b/validation/core/integration_test/component_internal_api/negative_interfaces_missing_from_internal_api_with_suggestions/internal_api_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 + +package package_a { + interface "diagnostics_interfac" as diagnostics_interfac { + + GetDiagnostics() + } + + interface "internal_interface" as internal_interface { + + GetData() + } +} + +@enduml diff --git a/validation/core/integration_test/component_public_api/BUILD b/validation/core/integration_test/component_public_api/BUILD index 95b8cb37..979d7bdc 100644 --- a/validation/core/integration_test/component_public_api/BUILD +++ b/validation/core/integration_test/component_public_api/BUILD @@ -19,6 +19,8 @@ filegroup( "//validation/core/integration_test/component_public_api/negative_case_sensitive:case_data", "//validation/core/integration_test/component_public_api/negative_public_api_lack_of_relationship:case_data", "//validation/core/integration_test/component_public_api/negative_public_api_missing:case_data", + "//validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion:case_data", + "//validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions:case_data", "//validation/core/integration_test/component_public_api/negative_public_api_wrong_type:case_data", "//validation/core/integration_test/component_public_api/positive_public_api_match:case_data", ], diff --git a/validation/core/integration_test/component_public_api/component_public_api_suite.rs b/validation/core/integration_test/component_public_api/component_public_api_suite.rs index 0a3de71c..908d5aea 100644 --- a/validation/core/integration_test/component_public_api/component_public_api_suite.rs +++ b/validation/core/integration_test/component_public_api/component_public_api_suite.rs @@ -59,6 +59,16 @@ fn negative_public_api_missing_suite_case() { assert_case("negative_public_api_missing"); } +#[test] +fn negative_public_api_missing_with_suggestion_suite_case() { + assert_case("negative_public_api_missing_with_suggestion"); +} + +#[test] +fn negative_public_api_missing_with_suggestions_suite_case() { + assert_case("negative_public_api_missing_with_suggestions"); +} + #[test] fn negative_public_api_wrong_type_suite_case() { assert_case("negative_public_api_wrong_type"); diff --git a/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/BUILD b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/BUILD new file mode 100644 index 00000000..071e5aec --- /dev/null +++ b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/BUILD @@ -0,0 +1,38 @@ +# ******************************************************************************* +# 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", "architectural_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +architectural_design( + name = "design", + maturity = "development", + public_api = ["public_api.puml"], + static = ["static_design.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/expected.yaml b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/expected.yaml new file mode 100644 index 00000000..730be9e6 --- /dev/null +++ b/validation/core/integration_test/component_public_api/negative_public_api_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: + - |- + [Interface] Public API interface(s) "SampleLibraryAPI" from the static diagram not found in the public API diagram. + Missing public APIs : "SampleLibraryAPI" + Static source file for "SampleLibraryAPI" : "validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/static_design.puml" + Static source line for "SampleLibraryAPI" : 20 + Suggestion for "SampleLibraryAPI" : Did you mean interface "SampleLibraryAP"? + Fix : Add public API declaration(s) "SampleLibraryAPI" in the public API diagram, or remove those interface declarations from the static diagram. diff --git a/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/public_api.puml b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/public_api.puml new file mode 100644 index 00000000..3be39902 --- /dev/null +++ b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/public_api.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 public_api + +interface "Sample Library AP" as SampleLibraryAP <> { + +GetNumber(): int +} + +@enduml diff --git a/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/static_design.puml b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/static_design.puml new file mode 100644 index 00000000..0e2d1f30 --- /dev/null +++ b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestion/static_design.puml @@ -0,0 +1,24 @@ +' ******************************************************************************* +' 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 static_design + +package "Sample Seooc" as sample_seooc <> { + portout sample_seooc_public_api_port +} + +interface "SampleLibraryAPI" as SampleLibraryAPI + +sample_seooc_public_api_port )-d- SampleLibraryAPI + +@enduml diff --git a/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/BUILD b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/BUILD new file mode 100644 index 00000000..071e5aec --- /dev/null +++ b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/BUILD @@ -0,0 +1,38 @@ +# ******************************************************************************* +# 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", "architectural_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +architectural_design( + name = "design", + maturity = "development", + public_api = ["public_api.puml"], + static = ["static_design.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:private"], + deps = [":design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//validation/core/integration_test:__subpackages__"], +) diff --git a/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/expected.yaml b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/expected.yaml new file mode 100644 index 00000000..b74308eb --- /dev/null +++ b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/expected.yaml @@ -0,0 +1,23 @@ +# ******************************************************************************* +# 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: |- + [Interface] Public API interface(s) "SampleLibraryAPI1", "SampleLibraryAPI2" from the static diagram not found in the public API diagram. + Missing public APIs : "SampleLibraryAPI1", "SampleLibraryAPI2" + Static source file for "SampleLibraryAPI1" : "validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/static_design.puml" + Static source line for "SampleLibraryAPI1" : 20 + Suggestion for "SampleLibraryAPI1" : Did you mean interface "SampleLibraryAP1"? + Static source file for "SampleLibraryAPI2" : "validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/static_design.puml" + Static source line for "SampleLibraryAPI2" : 21 + Suggestion for "SampleLibraryAPI2" : Did you mean interface "SampleLibraryAP2"? + Fix : Add public API declaration(s) "SampleLibraryAPI1", "SampleLibraryAPI2" in the public API diagram, or remove those interface declarations from the static diagram. diff --git a/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/public_api.puml b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/public_api.puml new file mode 100644 index 00000000..270f89c0 --- /dev/null +++ b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/public_api.puml @@ -0,0 +1,24 @@ +' ******************************************************************************* +' 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 public_api + +interface "Sample Library AP 1" as SampleLibraryAP1 <> { + +GetNumber(): int +} + +interface "Sample Library AP 2" as SampleLibraryAP2 <> { + +GetNumber(): int +} + +@enduml diff --git a/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/static_design.puml b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/static_design.puml new file mode 100644 index 00000000..4351edc1 --- /dev/null +++ b/validation/core/integration_test/component_public_api/negative_public_api_missing_with_suggestions/static_design.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 static_design + +package "Sample Seooc" as sample_seooc <> { + portout sample_seooc_public_api_port +} + +interface "SampleLibraryAPI1" as SampleLibraryAPI1 +interface "SampleLibraryAPI2" as SampleLibraryAPI2 + +sample_seooc_public_api_port )-d- SampleLibraryAPI1 +sample_seooc_public_api_port )-d- SampleLibraryAPI2 + +@enduml diff --git a/validation/core/integration_test/component_sequence/negative_missing_participant/expected.yaml b/validation/core/integration_test/component_sequence/negative_missing_participant/expected.yaml index a068742e..dacfca76 100644 --- a/validation/core/integration_test/component_sequence/negative_missing_participant/expected.yaml +++ b/validation/core/integration_test/component_sequence/negative_missing_participant/expected.yaml @@ -14,10 +14,11 @@ should_pass: false error_contains: - | [Naming] Alias "unit_3" from the component diagram not found in the sequence diagram. - Alias : "unit_3" - Component source file : "validation/core/integration_test/component_sequence/negative_missing_participant/component_diagram.puml" - Component source line : 20 - Fix : Add sequence participant "unit_3" in the sequence diagram, or remove it from the component diagram. + Alias : "unit_3" + Component source file : "validation/core/integration_test/component_sequence/negative_missing_participant/component_diagram.puml" + Component source line : 20 + Suggestion for "unit_3" : Did you mean "unit_1"? + Fix : Add sequence participant "unit_3" in the sequence diagram, or remove it from the component diagram. - | [Interface] Sequence-connected units "unit_1" and "unit_2" have no corresponding shared interface connection in the component diagram. Unit pair : "unit_1" <-> "unit_2" diff --git a/validation/core/integration_test/component_sequence/negative_mixed_mismatch/expected.yaml b/validation/core/integration_test/component_sequence/negative_mixed_mismatch/expected.yaml index 0fe42931..62faf753 100644 --- a/validation/core/integration_test/component_sequence/negative_mixed_mismatch/expected.yaml +++ b/validation/core/integration_test/component_sequence/negative_mixed_mismatch/expected.yaml @@ -14,16 +14,18 @@ should_pass: false error_contains: - | [Naming] Alias "unit_1" from the component diagram not found in the sequence diagram. - Alias : "unit_1" - Component source file : "validation/core/integration_test/component_sequence/negative_mixed_mismatch/component_diagram.puml" - Component source line : 18 - Fix : Add sequence participant "unit_1" in the sequence diagram, or remove it from the component diagram. + Alias : "unit_1" + Component source file : "validation/core/integration_test/component_sequence/negative_mixed_mismatch/component_diagram.puml" + Component source line : 18 + Suggestion for "unit_1" : Did you mean "unit_2"? + Fix : Add sequence participant "unit_1" in the sequence diagram, or remove it from the component diagram. - | [Naming] Participant "unit_3" from the sequence diagram not found in the component diagram. - Participant : "unit_3" - Sequence source file : "validation/core/integration_test/component_sequence/negative_mixed_mismatch/sequence_diagram.puml" - Sequence source line : 17 - Fix : Add component unit alias "unit_3" in the component diagram, or remove it from the sequence diagram. + Participant : "unit_3" + Sequence source file : "validation/core/integration_test/component_sequence/negative_mixed_mismatch/sequence_diagram.puml" + Sequence source line : 17 + Suggestion for "unit_3" : Did you mean "unit_1"? + Fix : Add component unit alias "unit_3" in the component diagram, or remove it from the sequence diagram. - | [Interface] Sequence-connected units "unit_2" and "unit_3" have no corresponding shared interface connection in the component diagram. Unit pair : "unit_2" <-> "unit_3" diff --git a/validation/core/integration_test/component_sequence/negative_orphan_participant/expected.yaml b/validation/core/integration_test/component_sequence/negative_orphan_participant/expected.yaml index d0c9ee70..fae4db1f 100644 --- a/validation/core/integration_test/component_sequence/negative_orphan_participant/expected.yaml +++ b/validation/core/integration_test/component_sequence/negative_orphan_participant/expected.yaml @@ -14,10 +14,11 @@ should_pass: false error_contains: - | [Naming] Participant "unit_3" from the sequence diagram not found in the component diagram. - Participant : "unit_3" - Sequence source file : "validation/core/integration_test/component_sequence/negative_orphan_participant/sequence_diagram.puml" - Sequence source line : 17 - Fix : Add component unit alias "unit_3" in the component diagram, or remove it from the sequence diagram. + Participant : "unit_3" + Sequence source file : "validation/core/integration_test/component_sequence/negative_orphan_participant/sequence_diagram.puml" + Sequence source line : 17 + Suggestion for "unit_3" : Did you mean "unit_1"? + Fix : Add component unit alias "unit_3" in the component diagram, or remove it from the sequence diagram. - | [Interface] Sequence-connected units "unit_1" and "unit_3" have no corresponding shared interface connection in the component diagram. Unit pair : "unit_1" <-> "unit_3" diff --git a/validation/core/integration_test/sequence_internal_api/BUILD b/validation/core/integration_test/sequence_internal_api/BUILD index f212e265..f73ba901 100644 --- a/validation/core/integration_test/sequence_internal_api/BUILD +++ b/validation/core/integration_test/sequence_internal_api/BUILD @@ -19,6 +19,7 @@ filegroup( "//validation/core/integration_test/sequence_internal_api/negative_interface_function_not_exercised:case_data", "//validation/core/integration_test/sequence_internal_api/negative_invalid_consumer_provider_direction:case_data", "//validation/core/integration_test/sequence_internal_api/negative_method_available_but_not_on_related_interface:case_data", + "//validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion:case_data", "//validation/core/integration_test/sequence_internal_api/negative_missing_method_in_related_interface:case_data", "//validation/core/integration_test/sequence_internal_api/positive_internal_api_method_match:case_data", "//validation/core/integration_test/sequence_internal_api/positive_self_call_method_match:case_data", diff --git a/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/BUILD b/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/BUILD new file mode 100644 index 00000000..47e01dfb --- /dev/null +++ b/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/BUILD @@ -0,0 +1,39 @@ +# ******************************************************************************* +# 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", "architectural_design") +load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle") + +architectural_design( + name = "design", + dynamic = ["sequence_diagram.puml"], + internal_api = ["internal_api_diagram.puml"], + maturity = "development", + static = ["component_diagram.puml"], + visibility = ["//visibility:private"], +) + +provider_fbs_fixture_bundle( + name = "fbs", + visibility = ["//visibility:public"], + deps = [":design"], +) + +filegroup( + name = "case_data", + srcs = [ + "expected.yaml", + ":fbs", + ], + visibility = ["//visibility:public"], +) diff --git a/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/component_diagram.puml b/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/component_diagram.puml new file mode 100644 index 00000000..c87543a4 --- /dev/null +++ b/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/component_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 component_diagram + +package "Package A" as package_a { + component "Component A" as component_a <> { + component "Unit 1" as unit_1 <> + component "Unit 2" as unit_2 <> + } + + interface "InternalInterface" as InternalInterface + unit_1 -( InternalInterface + unit_2 )- InternalInterface +} + +@enduml diff --git a/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/expected.yaml b/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/expected.yaml new file mode 100644 index 00000000..36d0512f --- /dev/null +++ b/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/expected.yaml @@ -0,0 +1,29 @@ +# ******************************************************************************* +# 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 "GetData" from sequence call "unit_1" -> "unit_2" : "GetData" in the sequence diagram not found in the internal API diagram. + Sequence call : "unit_1" -> "unit_2" : "GetData" + Sequence source file : "validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/sequence_diagram.puml" + Sequence source line : 19 + Detail : sequence function name was not found in available interface methods + Suggestion for "GetData" : Did you mean method "GetDate"? + Fix : Add method "GetData" in a matching internal API interface in the internal API diagram, or remove sequence function "GetData" in sequence call "unit_1" -> "unit_2" : "GetData" in the sequence diagram. + - |- + [Coverage] Methods "GetDate" declared on internal API interface "package_a.InternalInterface" in the internal API diagram are not exercised in the sequence diagram. + Interface id : "package_a.InternalInterface" + Internal API source file : "validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/internal_api_diagram.puml" + Internal API source line : 17 + Missing functions : "GetDate" + Fix : Add sequence interactions for functions "GetDate" in the sequence diagram, or remove function declarations "GetDate" in internal API interface "package_a.InternalInterface". diff --git a/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/internal_api_diagram.puml b/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/internal_api_diagram.puml new file mode 100644 index 00000000..3d1c2b02 --- /dev/null +++ b/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/internal_api_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 + +package package_a { + interface "InternalInterface" as InternalInterface { + + GetDate() + } +} + +@enduml diff --git a/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/sequence_diagram.puml b/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/sequence_diagram.puml new file mode 100644 index 00000000..32938db5 --- /dev/null +++ b/validation/core/integration_test/sequence_internal_api/negative_missing_method_in_available_interfaces_with_suggestion/sequence_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 sequence_diagram + +participant "Unit 1" as unit_1 <> +participant "Unit 2" as unit_2 <> + +unit_1 -> unit_2 : GetData() +unit_2 --> unit_1 : Ack + +@enduml diff --git a/validation/core/integration_test/sequence_internal_api/sequence_internal_api_suite.rs b/validation/core/integration_test/sequence_internal_api/sequence_internal_api_suite.rs index 0fec6d6d..6d146652 100644 --- a/validation/core/integration_test/sequence_internal_api/sequence_internal_api_suite.rs +++ b/validation/core/integration_test/sequence_internal_api/sequence_internal_api_suite.rs @@ -72,6 +72,11 @@ fn negative_missing_method_in_related_interface_suite_case() { assert_case("negative_missing_method_in_related_interface"); } +#[test] +fn negative_missing_method_in_available_interfaces_with_suggestion_suite_case() { + assert_case("negative_missing_method_in_available_interfaces_with_suggestion"); +} + #[test] fn negative_method_available_but_not_on_related_interface_suite_case() { assert_case("negative_method_available_but_not_on_related_interface"); diff --git a/validation/core/src/results/error_models.rs b/validation/core/src/results/error_models.rs index 951e64d0..f1160cfe 100644 --- a/validation/core/src/results/error_models.rs +++ b/validation/core/src/results/error_models.rs @@ -96,6 +96,25 @@ impl ErrorBuilder { self } + pub fn suggest( + self, + original_name: &str, + suggestion_subject: Option<&str>, + suggested_name: &str, + ) -> Self { + let suggestion_text = match suggestion_subject { + Some(suggestion_subject) => { + format!("Did you mean {suggestion_subject} \"{suggested_name}\"?") + } + None => format!("Did you mean \"{suggested_name}\"?"), + }; + + self.field( + format!("suggestion for \"{original_name}\""), + suggestion_text, + ) + } + pub fn build(self) -> String { let label_width = self .fields @@ -123,3 +142,32 @@ impl ErrorBuilder { message } } + +#[cfg(test)] +mod tests { + use super::{ErrorBuilder, ErrorCategory}; + + #[test] + fn suggest_formats_message_with_subject() { + let message = ErrorBuilder::new(ErrorCategory::Naming) + .suggest("Srvce", Some("class"), "Service") + .build(); + + assert_eq!( + message, + "[Naming] \n Suggestion for \"Srvce\" : Did you mean class \"Service\"?" + ); + } + + #[test] + fn suggest_formats_message_without_subject() { + let message = ErrorBuilder::new(ErrorCategory::Naming) + .suggest("Srvce", None, "Service") + .build(); + + assert_eq!( + message, + "[Naming] \n Suggestion for \"Srvce\" : Did you mean \"Service\"?" + ); + } +} diff --git a/validation/core/src/validators/bazel_component_validator.rs b/validation/core/src/validators/bazel_component_validator.rs index a44090a8..8ce0c00d 100644 --- a/validation/core/src/validators/bazel_component_validator.rs +++ b/validation/core/src/validators/bazel_component_validator.rs @@ -19,6 +19,7 @@ use std::collections::{BTreeMap, BTreeSet}; +use super::shared::best_string_suggestion; use crate::models::{BazelArchitecture, ComponentDiagramArchitecture, LogicComponent}; use crate::results::{ErrorBuilder, ErrorCategory}; use crate::{Diagnostics, ValidationResult}; @@ -93,12 +94,20 @@ impl BazelComponentValidator { if !diagram_set.contains_key(key) { let (name, parent) = key; let parent_str = Self::parent_display(parent, default_parent); + let suggested_alias = best_string_suggestion( + name, + diagram_set + .keys() + .filter(|(_, candidate_parent)| candidate_parent == parent) + .map(|(candidate_name, _)| candidate_name.as_str()), + ); self.result.add_failure(Self::format_missing( display_type, stereotype, name, &parent_str, label, + suggested_alias.as_deref(), )); } } @@ -108,11 +117,19 @@ impl BazelComponentValidator { if !bazel_set.contains_key(key) { let (name, parent) = key; let parent_str = Self::parent_display(parent, default_parent); + let suggested_alias = best_string_suggestion( + name, + bazel_set + .keys() + .filter(|(_, candidate_parent)| candidate_parent == parent) + .map(|(candidate_name, _)| candidate_name.as_str()), + ); self.result.add_failure(Self::format_extra( display_type, name, &parent_str, entity, + suggested_alias.as_deref(), )); } } @@ -176,15 +193,24 @@ impl BazelComponentValidator { name: &str, parent_str: &str, label: &str, + suggested_alias: Option<&str>, ) -> String { - ErrorBuilder::new(ErrorCategory::Naming) + let error = ErrorBuilder::new(ErrorCategory::Naming) .title(format!( "{display_type} \"{name}\" from Bazel not found in the PlantUML component diagram" )) .field("alias", format!("\"{name}\"")) .field("parent", parent_str) .field("stereotype", format!("<<{stereotype}>>")) - .field("bazel label", label) + .field("bazel label", label); + + let error = if let Some(suggested_alias) = suggested_alias { + error.suggest(name, Some(display_type), suggested_alias) + } else { + error + }; + + error .fix(format!( "add {display_type} \"{name}\" with stereotype <<{stereotype}>> in the PlantUML component diagram, or remove it from Bazel" )) @@ -196,17 +222,26 @@ impl BazelComponentValidator { name: &str, parent_str: &str, entity: &LogicComponent, + suggested_alias: Option<&str>, ) -> String { let (source_file, source_line) = entity.source_location.display(); - ErrorBuilder::new(ErrorCategory::Naming) + let error = ErrorBuilder::new(ErrorCategory::Naming) .title(format!( "{entity_type} \"{name}\" from the PlantUML component diagram not found in Bazel" )) .field("alias", format!("\"{name}\"")) .field("parent", parent_str) .field("component source file", format!("\"{source_file}\"")) - .field("component source line", source_line.to_string()) + .field("component source line", source_line.to_string()); + + let error = if let Some(suggested_alias) = suggested_alias { + error.suggest(name, Some(entity_type), suggested_alias) + } else { + error + }; + + error .fix(format!( "add the corresponding Bazel {entity_type} definition for \"{name}\", or remove it from the PlantUML component diagram" )) diff --git a/validation/core/src/validators/class_design_implementation_validator.rs b/validation/core/src/validators/class_design_implementation_validator.rs index db3ac953..b8c74643 100644 --- a/validation/core/src/validators/class_design_implementation_validator.rs +++ b/validation/core/src/validators/class_design_implementation_validator.rs @@ -14,6 +14,7 @@ //! Class implementation validation: compare unit design class diagrams with //! C++ implementation produced by the C++ parser. +use super::shared::best_string_suggestion; use crate::models::ClassEntityIndex; use crate::results::{ErrorBuilder, ErrorCategory}; use crate::ValidationResult; @@ -67,8 +68,16 @@ impl ClassDesignImplementationValidator { .find_by_id(&design_entity.id) .or_else(|| implementation_classes.find_by_id(&normalized_design_id)) else { - self.result - .add_failure(Self::format_missing_class(design_entity)); + let suggested_class = best_string_suggestion( + &design_entity.id, + implementation_classes + .entities() + .map(|entity| entity.id.as_str()), + ); + self.result.add_failure(Self::format_missing_class( + design_entity, + suggested_class.as_deref(), + )); continue; }; @@ -148,6 +157,11 @@ impl ClassDesignImplementationValidator { design_entity, "type_alias", &design_alias.alias, + best_string_suggestion( + &design_alias.alias, + implementation_aliases.keys().copied(), + ) + .as_deref(), )), } } @@ -173,6 +187,11 @@ impl ClassDesignImplementationValidator { design_entity, "variable", &design_variable.name, + best_string_suggestion( + &design_variable.name, + implementation_variables.keys().copied(), + ) + .as_deref(), )), } } @@ -257,6 +276,11 @@ impl ClassDesignImplementationValidator { design_entity, "method", &key, + best_string_suggestion( + &key, + implementation_methods.keys().map(String::as_str), + ) + .as_deref(), )), } } @@ -412,6 +436,11 @@ impl ClassDesignImplementationValidator { design_entity, "enum_literal", &design_literal.name, + best_string_suggestion( + &design_literal.name, + implementation_literals.keys().copied(), + ) + .as_deref(), )), } } @@ -440,17 +469,29 @@ impl ClassDesignImplementationValidator { &relationship_display_name(implementation_relationship), )) } - None => self.result.add_failure(Self::format_missing_member( - design_entity, - "relationship", - &display_name, - )), + None => { + let implementation_relationship_names = implementation_entity + .relationships + .iter() + .map(relationship_display_name) + .collect::>(); + self.result.add_failure(Self::format_missing_member( + design_entity, + "relationship", + &display_name, + best_string_suggestion( + &display_name, + implementation_relationship_names.iter().map(String::as_str), + ) + .as_deref(), + )) + } } } } - fn format_missing_class(entity: &SimpleEntity) -> String { - ErrorBuilder::new(ErrorCategory::Class) + fn format_missing_class(entity: &SimpleEntity, suggested_class: Option<&str>) -> String { + let error = ErrorBuilder::new(ErrorCategory::Class) .title(format!( "class \"{}\" from the unit design not found in the C++ class implementation", entity.id @@ -461,16 +502,24 @@ impl ClassDesignImplementationValidator { .fix(format!( "add implementation class \"{}\" in the C++ class implementation, or remove it from the unit design", entity.id - )) - .build() + )); + + let error = if let Some(suggested_class) = suggested_class { + error.suggest(&entity.id, Some("class"), suggested_class) + } else { + error + }; + + error.build() } fn format_missing_member( design_entity: &SimpleEntity, member_type: &str, member_name: &str, + suggested_member: Option<&str>, ) -> String { - ErrorBuilder::new(ErrorCategory::Member) + let error = ErrorBuilder::new(ErrorCategory::Member) .title(format!( "{member_type} \"{member_name}\" from entity \"{}\" in the unit design not found in the C++ class implementation", design_entity.id @@ -485,8 +534,15 @@ impl ClassDesignImplementationValidator { .fix(format!( "add {member_type} \"{member_name}\" to entity \"{}\" in the C++ class implementation, or remove it from the unit design", design_entity.id - )) - .build() + )); + + let error = if let Some(suggested_member) = suggested_member { + error.suggest(member_name, Some(member_type), suggested_member) + } else { + error + }; + + error.build() } fn format_mismatch( diff --git a/validation/core/src/validators/component_internal_api_validator.rs b/validation/core/src/validators/component_internal_api_validator.rs index e903557d..f74d84fd 100644 --- a/validation/core/src/validators/component_internal_api_validator.rs +++ b/validation/core/src/validators/component_internal_api_validator.rs @@ -16,7 +16,7 @@ use std::collections::{BTreeMap, BTreeSet}; -use super::shared::format_name_list; +use super::shared::{best_string_suggestion, format_name_list}; use crate::models::{ComponentDiagramArchitecture, InternalApiIndex, LogicComponentExt}; use crate::results::{ErrorBuilder, ErrorCategory}; use crate::{Diagnostics, ValidationResult}; @@ -77,6 +77,7 @@ impl ComponentInternalApiValidator { .add_failure(format_missing_internal_api_interface_error( &missing_interfaces, &self.component_interface_sources, + &self.internal_api_interface_ids, )); } } @@ -119,6 +120,7 @@ fn collect_internal_api_interface_ids(internal_api_diagram: &InternalApiIndex) - fn format_missing_internal_api_interface_error( missing_internal_api_interfaces: &BTreeSet, component_interface_sources: &BTreeMap, + internal_api_interface_ids: &BTreeSet, ) -> String { let missing_interfaces = format_name_list(missing_internal_api_interfaces); @@ -141,6 +143,13 @@ fn format_missing_internal_api_interface_error( source_line.to_string(), ); } + + if let Some(suggested_interface) = best_string_suggestion( + interface_id, + internal_api_interface_ids.iter().map(String::as_str), + ) { + error = error.suggest(interface_id, Some("interface"), &suggested_interface); + } } error diff --git a/validation/core/src/validators/component_public_api_validator.rs b/validation/core/src/validators/component_public_api_validator.rs index 1cb35d2c..22ff2244 100644 --- a/validation/core/src/validators/component_public_api_validator.rs +++ b/validation/core/src/validators/component_public_api_validator.rs @@ -16,7 +16,7 @@ use std::collections::{BTreeMap, BTreeSet}; -use super::shared::format_name_list; +use super::shared::{best_string_suggestion, format_name_list}; use crate::models::{ComponentDiagramArchitecture, LogicComponentExt, PublicApiIndex}; use crate::results::{ErrorBuilder, ErrorCategory}; use crate::{Diagnostics, ValidationResult}; @@ -194,6 +194,17 @@ fn format_missing_public_api_error( source_line.to_string(), ); } + + if case_mismatch_public_apis.contains(interface_id) { + continue; + } + + if let Some(suggested_interface) = best_string_suggestion( + interface_id, + design_public_api_ids.iter().map(String::as_str), + ) { + error = error.suggest(interface_id, Some("interface"), &suggested_interface); + } } error diff --git a/validation/core/src/validators/component_sequence_validator.rs b/validation/core/src/validators/component_sequence_validator.rs index 06febb2f..a5cc8a37 100644 --- a/validation/core/src/validators/component_sequence_validator.rs +++ b/validation/core/src/validators/component_sequence_validator.rs @@ -19,8 +19,8 @@ use std::collections::{BTreeMap, BTreeSet}; use sequence_logic::SourceLocation; use super::shared::{ - build_observed_call_contexts, build_unit_bindings, format_name_list, intersect_interfaces, - SequenceCallContext, UnitBindings, + 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::results::{ErrorBuilder, ErrorCategory}; @@ -127,19 +127,32 @@ impl<'a> ComponentSequenceValidator<'a> { .map(|source_location| source_location.display()) .unwrap_or_default(); - self.result.add_failure( - ErrorBuilder::new(ErrorCategory::Naming) - .title(format!( - "alias \"{alias}\" from the component diagram not found in the sequence diagram" - )) - .field("alias", format!("\"{alias}\"")) - .field("component source file", format!("\"{source_file}\"")) - .field("component source line", source_line.to_string()) - .fix(format!( - "add sequence participant \"{alias}\" in the sequence diagram, or remove it from the component diagram" - )) - .build(), - ); + let error = ErrorBuilder::new(ErrorCategory::Naming) + .title(format!( + "alias \"{alias}\" from the component diagram not found in the sequence diagram" + )) + .field("alias", format!("\"{alias}\"")) + .field("component source file", format!("\"{source_file}\"")) + .field("component source line", source_line.to_string()) + .fix(format!( + "add sequence participant \"{alias}\" in the sequence diagram, or remove it from the component diagram" + )); + + let error = if let Some(suggested_name) = best_string_suggestion( + alias, + self.participants + .keys() + .filter(|participant| !is_external_endpoint(participant)) + .map(String::as_str), + ) + .as_deref() + { + error.suggest(alias, None, suggested_name) + } else { + error + }; + + self.result.add_failure(error.build()); } for participant in self.participants.keys().filter(|participant| { @@ -147,19 +160,27 @@ impl<'a> ComponentSequenceValidator<'a> { }) { let (source_file, source_line) = self.participants[participant].display(); - self.result.add_failure( - ErrorBuilder::new(ErrorCategory::Naming) - .title(format!( - "participant \"{participant}\" from the sequence diagram not found in the component diagram" - )) - .field("participant", format!("\"{participant}\"")) - .field("sequence source file", format!("\"{source_file}\"")) - .field("sequence source line", source_line.to_string()) - .fix(format!( - "add component unit alias \"{participant}\" in the component diagram, or remove it from the sequence diagram" - )) - .build(), - ); + let error = ErrorBuilder::new(ErrorCategory::Naming) + .title(format!( + "participant \"{participant}\" from the sequence diagram not found in the component diagram" + )) + .field("participant", format!("\"{participant}\"")) + .field("sequence source file", format!("\"{source_file}\"")) + .field("sequence source line", source_line.to_string()) + .fix(format!( + "add component unit alias \"{participant}\" in the component diagram, or remove it from the sequence diagram" + )); + + let error = if let Some(suggested_name) = + best_string_suggestion(participant, self.unit_bindings.keys().map(String::as_str)) + .as_deref() + { + error.suggest(participant, None, suggested_name) + } else { + error + }; + + self.result.add_failure(error.build()); } } diff --git a/validation/core/src/validators/sequence_internal_api_validator.rs b/validation/core/src/validators/sequence_internal_api_validator.rs index b4bb3ed0..1d42f4be 100644 --- a/validation/core/src/validators/sequence_internal_api_validator.rs +++ b/validation/core/src/validators/sequence_internal_api_validator.rs @@ -18,8 +18,9 @@ use std::collections::{BTreeMap, BTreeSet}; use super::shared::{ - build_observed_call_contexts, build_unit_bindings, extract_method_name, format_name_list, - format_sequence_call, intersect_interfaces, SequenceCallContext, UnitBindings, UnitInterfaces, + best_string_suggestion, build_observed_call_contexts, build_unit_bindings, extract_method_name, + format_name_list, format_sequence_call, intersect_interfaces, SequenceCallContext, + UnitBindings, UnitInterfaces, }; use crate::models::{ ComponentDiagramArchitecture, InternalApiIndex, InternalApiInterface, LogicComponentExt, @@ -156,10 +157,19 @@ impl<'a> SequenceInternalApiValidator<'a> { ); if matching_interfaces.is_empty() { + let candidate_method_names = collect_method_candidates_for_interfaces( + &self.internal_api_interfaces_by_id, + &component_context.all_interfaces, + ); + let suggested_method = best_string_suggestion( + method_name, + candidate_method_names.iter().map(String::as_str), + ); return Some(format_sequence_method_consistency_error( call_context, method_name, "sequence function name was not found in available interface methods", + suggested_method.as_deref(), )); } @@ -200,10 +210,23 @@ impl<'a> SequenceInternalApiValidator<'a> { intersect_interfaces(&caller_matching_interfaces, &callee_matching_interfaces); if shared_method_interfaces.is_empty() { + let shared_interface_ids = collect_shared_internal_api_interface_ids( + &self.internal_api_interfaces_by_id, + call_context, + ); + let candidate_method_names = collect_method_candidates_for_interfaces( + &self.internal_api_interfaces_by_id, + &shared_interface_ids, + ); + let suggested_method = best_string_suggestion( + method_name, + candidate_method_names.iter().map(String::as_str), + ); return Some(format_sequence_method_consistency_error( call_context, method_name, "sequence function name was not found in the related interface methods", + suggested_method.as_deref(), )); } @@ -401,6 +424,30 @@ fn matching_interfaces_with_method( .collect() } +fn collect_method_candidates_for_interfaces( + internal_api_interfaces_by_id: &BTreeMap, + interface_ids: &BTreeSet, +) -> BTreeSet { + interface_ids + .iter() + .filter_map(|interface_id| internal_api_interfaces_by_id.get(interface_id.as_str())) + .flat_map(|interface| interface.method_names.iter().cloned()) + .collect() +} + +fn collect_shared_internal_api_interface_ids( + internal_api_interfaces_by_id: &BTreeMap, + call_context: &SequenceCallContext<'_>, +) -> BTreeSet { + intersect_interfaces( + &call_context.caller_interfaces, + &call_context.callee_interfaces, + ) + .into_iter() + .filter(|interface_id| internal_api_interfaces_by_id.contains_key(interface_id.as_str())) + .collect() +} + fn role_interfaces(bindings: &UnitInterfaces) -> BTreeSet { bindings .required_interfaces @@ -478,6 +525,7 @@ fn format_sequence_method_consistency_error( call_context: &SequenceCallContext<'_>, method_name: &str, description: &str, + suggested_method: Option<&str>, ) -> String { let sequence_call = format_sequence_call( call_context.caller_unit, @@ -486,14 +534,20 @@ fn format_sequence_method_consistency_error( ); let (source_file, source_line) = call_context.source_location.display(); - ErrorBuilder::new(ErrorCategory::Method) + let mut error = ErrorBuilder::new(ErrorCategory::Method) .title(format!( "sequence function \"{method_name}\" from sequence call {sequence_call} in the sequence diagram not found in the internal API diagram" )) .field("sequence call", sequence_call.clone()) .field("sequence source file", format!("\"{source_file}\"")) .field("sequence source line", source_line.to_string()) - .field("detail", description) + .field("detail", description); + + if let Some(suggested_method) = suggested_method { + error = error.suggest(method_name, Some("method"), suggested_method); + } + + error .fix(format!( "add method \"{method_name}\" in a matching internal API interface in the internal API diagram, or remove sequence function \"{method_name}\" in sequence call {sequence_call} in the sequence diagram" )) diff --git a/validation/core/src/validators/shared/helpers.rs b/validation/core/src/validators/shared/helpers.rs index 0c2ba682..789e1f08 100644 --- a/validation/core/src/validators/shared/helpers.rs +++ b/validation/core/src/validators/shared/helpers.rs @@ -15,6 +15,10 @@ use std::collections::BTreeSet; +use strsim::jaro_winkler; + +pub(in crate::validators) const DEFAULT_SUGGESTION_THRESHOLD: f64 = 0.75; + pub(in crate::validators) fn format_name_list(names: &BTreeSet) -> String { if names.is_empty() { return "".to_string(); @@ -48,3 +52,55 @@ pub(in crate::validators) fn intersect_interfaces( .cloned() .collect() } + +pub(in crate::validators) fn best_string_suggestion<'a>( + name: &str, + candidates: impl IntoIterator, +) -> Option { + let mut best_candidate: Option<&str> = None; + let mut best_score = 0.0; + + for candidate in candidates { + let score = jaro_winkler(name, candidate); + if score > best_score { + best_score = score; + best_candidate = Some(candidate); + } + } + + if best_score < DEFAULT_SUGGESTION_THRESHOLD { + return None; + } + + best_candidate.map(str::to_string) +} + +#[cfg(test)] +mod tests { + use super::{best_string_suggestion, DEFAULT_SUGGESTION_THRESHOLD}; + use strsim::jaro_winkler; + + #[test] + fn best_string_suggestion_returns_none_for_empty_candidates() { + assert_eq!(best_string_suggestion("Service", std::iter::empty()), None); + } + + #[test] + fn best_string_suggestion_accepts_exact_threshold_match() { + let score = jaro_winkler("a", "baaa"); + assert_eq!(score, DEFAULT_SUGGESTION_THRESHOLD); + + assert_eq!( + best_string_suggestion("a", ["baaa"]), + Some("baaa".to_string()) + ); + } + + #[test] + fn best_string_suggestion_rejects_below_threshold_match() { + let score = jaro_winkler("abc", "xyz"); + assert!(score < DEFAULT_SUGGESTION_THRESHOLD); + + assert_eq!(best_string_suggestion("abc", ["xyz"]), None); + } +} diff --git a/validation/core/src/validators/shared/mod.rs b/validation/core/src/validators/shared/mod.rs index 1eca4cad..f67af557 100644 --- a/validation/core/src/validators/shared/mod.rs +++ b/validation/core/src/validators/shared/mod.rs @@ -21,5 +21,6 @@ pub(in crate::validators) use diagram_analysis::{ UnitInterfaces, }; pub(in crate::validators) use helpers::{ - extract_method_name, format_name_list, format_sequence_call, intersect_interfaces, + best_string_suggestion, extract_method_name, format_name_list, format_sequence_call, + intersect_interfaces, };