diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/.gitignore b/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/.gitignore new file mode 100644 index 0000000000..afce51184c --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/.gitignore @@ -0,0 +1,2 @@ +/.aadlbin-gen/ +/instances/ diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/.project b/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/.project new file mode 100644 index 0000000000..a79a1d80a5 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/.project @@ -0,0 +1,18 @@ + + + issue2821 + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.osate.core.aadlnature + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/InvalidBranches.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/InvalidBranches.aadl new file mode 100644 index 0000000000..c6be4d0fee --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/InvalidBranches.aadl @@ -0,0 +1,57 @@ +package InvalidBranches +public + with ProbabilityProperties, Issue2821; + + system duplicate_same + annex EMV2 {** + use behavior Issue2821::machine; + component error behavior + transitions + t: state1 -[event1]-> (same state with ProbabilityProperties::probability, same state with 0.125); + end component; + **}; + end duplicate_same; + + system duplicate_others + annex EMV2 {** + use behavior Issue2821::machine; + component error behavior + transitions + t: state1 -[event1]-> (state2 with ProbabilityProperties::probability, same state with others, state3 with others); + end component; + **}; + end duplicate_others; + + system known_property + annex EMV2 {** + use behavior Issue2821::machine; + component error behavior + transitions + t: state1 -[event1]-> (state2 with 0.125, state3 with ProbabilityProperties::probability); + end component; + properties + ProbabilityProperties::probability => 0.5 applies to t; + **}; + end known_property; + + system known_literals + annex EMV2 {** + use behavior Issue2821::machine; + component error behavior + transitions + t: state1 -[event1]-> (state2 with 0.125, state3 with 0.5); + end component; + **}; + end known_literals; + + system exhausted_remainder + annex EMV2 {** + use behavior Issue2821::machine; + component error behavior + transitions + t: state1 -[event1]-> (state2 with 1.0, same state with others); + end component; + **}; + end exhausted_remainder; + +end InvalidBranches; diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/Issue2821.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/Issue2821.aadl new file mode 100644 index 0000000000..56bd0a8775 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/Issue2821.aadl @@ -0,0 +1,79 @@ +package Issue2821 +public + with ProbabilityProperties; + + system s + end s; + + system implementation s.base + annex EMV2 {** + use behavior Issue2821::machine; + component error behavior + transitions + t: state1 -[event1]-> (state2 with 0.125, state3 with ProbabilityProperties::probability); + end component; + **}; + end s.base; + + system implementation s.extended extends s.base + annex EMV2 {** + properties + ProbabilityProperties::probability => 0.875 applies to t; + **}; + end s.extended; + + system container + end container; + + system implementation container.i + subcomponents + child: system s.base; + annex EMV2 {** + properties + ProbabilityProperties::probability => 0.875 applies to ^child@t; + **}; + end container.i; + + system known_value + annex EMV2 {** + use behavior Issue2821::machine; + component error behavior + transitions + t: state1 -[event1]-> (state2 with 0.125, state3 with ProbabilityProperties::probability); + end component; + properties + ProbabilityProperties::probability => 0.875 applies to t; + **}; + end known_value; + + system unknown_with_others + annex EMV2 {** + use behavior Issue2821::machine; + component error behavior + transitions + t: state1 -[event1]-> (state2 with 0.125, state3 with ProbabilityProperties::probability, same state with others); + end component; + **}; + end unknown_with_others; + + annex EMV2 {** + error behavior machine + events + event1: error event; + states + state1: initial state; + state2: state; + state3: state; + end behavior; + + error behavior deferred + events + event1: error event; + states + state1: initial state; + state2: state; + transitions + t: state1 -[event1]-> (state2 with 0.125, same state with ProbabilityProperties::probability); + end behavior; + **}; +end Issue2821; diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/ProbabilityProperties.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/ProbabilityProperties.aadl new file mode 100644 index 0000000000..419ecc2aae --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2821/ProbabilityProperties.aadl @@ -0,0 +1,3 @@ +property set ProbabilityProperties is + probability: aadlreal applies to (all); +end ProbabilityProperties; diff --git a/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/errormodelscopeprovider/PropertyReferenceTest.java b/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/errormodelscopeprovider/PropertyReferenceTest.java index e461494df9..3d1301d5ff 100644 --- a/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/errormodelscopeprovider/PropertyReferenceTest.java +++ b/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/errormodelscopeprovider/PropertyReferenceTest.java @@ -253,8 +253,7 @@ public void testBranchValue() throws Exception { Assert.assertEquals("bvr", errorBehaviorStateMachine.getName()); var errorBehaviorTransition = (errorBehaviorStateMachine.getTransitions()).getFirst(); Assert.assertEquals("transition1", errorBehaviorTransition.getName()); - AssertHelper.assertError(errorBehaviorTransition, lib1TestResult.getIssues(), lib1IssueCollection, - "Sum of branch probabilities must be 1"); + // The library leaves the probability undefined so a using classifier can supply it. this.assertHelper.assertScope(errorBehaviorTransition.getDestinationBranches().get(1).getValue(), ErrorModelPackage.eINSTANCE.getBranchValue_Symboliclabel(), expectedScope); diff --git a/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2821Test.java b/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2821Test.java new file mode 100644 index 0000000000..9039408366 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2821Test.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2004-2026 Carnegie Mellon University and others. (see Contributors file). + * All Rights Reserved. + * + * NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE + * OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT + * MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * SPDX-License-Identifier: EPL-2.0 + * + * Created, in part, with funding and support from the United States Government. (see Acknowledgments file). + * + * This program includes and/or can make use of certain third party source code, object code, documentation and other + * files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system + * configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and + * conditions contained in any such Third Party Software or separate license file distributed with such Third Party + * Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici- + * aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li- + * censes only apply to the Third Party Software and not any other portion of this program or this program as a whole. + */ +package org.osate.aadl2.errormodel.tests.issues; + +import java.util.ArrayList; + +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.XtextRunner; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.osate.aadl2.AadlPackage; +import org.osate.aadl2.DefaultAnnexSubclause; +import org.osate.aadl2.errormodel.tests.ErrorModelInjectorProvider; +import org.osate.testsupport.AssertHelper; +import org.osate.testsupport.TestHelper; +import org.osate.xtext.aadl2.errormodel.errorModel.ErrorModelSubclause; + +import com.google.inject.Inject; +import com.itemis.xtext.testing.FluentIssueCollection; +import com.itemis.xtext.testing.XtextTest; + +@RunWith(XtextRunner.class) +@InjectWith(ErrorModelInjectorProvider.class) +public class Issue2821Test extends XtextTest { + private static final String PROJECT_LOCATION = "org.osate.aadl2.errormodel.tests/models/issue2821/"; + private static final String PROPERTIES = PROJECT_LOCATION + "ProbabilityProperties.aadl"; + + @Inject + private TestHelper testHelper; + + @Inject + private ValidationTestHelper validationHelper; + + @Test + public void allowProbabilitiesSuppliedInLaterContexts() { + validationHelper.assertNoIssues(testHelper.parseFile(PROJECT_LOCATION + "Issue2821.aadl", PROPERTIES)); + } + + @Test + public void preserveStructuralChecksAndKnownProbabilitySums() throws Exception { + var result = issues = testHelper.testFile(PROJECT_LOCATION + "InvalidBranches.aadl", PROPERTIES, + PROJECT_LOCATION + "Issue2821.aadl"); + var expected = new FluentIssueCollection(result.getResource(), new ArrayList<>(), new ArrayList<>()); + var pkg = (AadlPackage) result.getResource().getContents().getFirst(); + for (var classifier : pkg.getPublicSection().getOwnedClassifiers()) { + var annex = (ErrorModelSubclause) ((DefaultAnnexSubclause) classifier.getOwnedAnnexSubclauses().getFirst()) + .getParsedAnnexSubclause(); + var message = switch (classifier.getName()) { + case "duplicate_same" -> "More than one same state branch"; + case "duplicate_others" -> "More than one other branch"; + case "exhausted_remainder" -> "Sum of branch probabilities must be less than 1 due to 'others'"; + default -> "Sum of branch probabilities must be 1"; + }; + AssertHelper.assertError(annex.getTransitions().getFirst(), result.getIssues(), expected, message); + } + expected.sizeIs(5); + assertConstraints(expected); + } +} diff --git a/emv2/org.osate.xtext.aadl2.errormodel/src/org/osate/xtext/aadl2/errormodel/validation/ErrorModelValidator.java b/emv2/org.osate.xtext.aadl2.errormodel/src/org/osate/xtext/aadl2/errormodel/validation/ErrorModelValidator.java index e00cc0c909..0e73d130ba 100644 --- a/emv2/org.osate.xtext.aadl2.errormodel/src/org/osate/xtext/aadl2/errormodel/validation/ErrorModelValidator.java +++ b/emv2/org.osate.xtext.aadl2.errormodel/src/org/osate/xtext/aadl2/errormodel/validation/ErrorModelValidator.java @@ -1096,6 +1096,7 @@ private void checkBranches(ErrorBehaviorTransition ebt) { EList branches = ebt.getDestinationBranches(); boolean foundsteady = false; boolean foundothers = false; + boolean allProbabilitiesKnown = true; BigDecimal prob = new BigDecimal(0.0, MathContext.UNLIMITED); if (branches.isEmpty()) { return; @@ -1122,12 +1123,18 @@ private void checkBranches(ErrorBehaviorTransition ebt) { } else if (sl != null) { Classifier cl = EMV2Util.getAssociatedClassifier(ebt); List pa = EMV2Properties.getProperty(sl.getQualifiedName(), cl, ebt, null); + if (pa.isEmpty()) { + allProbabilitiesKnown = false; + } for (EMV2PropertyAssociation emv2PropertyAssociation : pa) { prob = prob.add(new BigDecimal(EMV2Properties.getRealValue(emv2PropertyAssociation), MathContext.UNLIMITED)); } } } + if (!allProbabilitiesKnown) { + return; + } if (!foundothers && prob.compareTo(new BigDecimal(1.0)) != 0) { error(ebt, "Sum of branch probabilities must be 1"); }