diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/.gitignore b/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/.gitignore new file mode 100644 index 0000000000..afce51184c --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/.gitignore @@ -0,0 +1,2 @@ +/.aadlbin-gen/ +/instances/ diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/.project b/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/.project new file mode 100644 index 0000000000..0195361dd2 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/.project @@ -0,0 +1,18 @@ + + + issue2817 + + + + + + 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/issue2817/Issue2817.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/Issue2817.aadl new file mode 100644 index 0000000000..c7ba595ba6 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/Issue2817.aadl @@ -0,0 +1,29 @@ +package Issue2817 +public + annex EMV2 {** + error behavior Machine + states + state1: initial state; + state2: state; + end behavior; + **}; + + system S + annex EMV2 {** + use types ErrorLibrary; + use behavior Issue2817::Machine; + component error behavior + events + typed: error event {CommonErrors}; + untyped: error event; + recovery: recover event; + repair1: repair event; + transitions + typed_event: state1 -[typed {ServiceError} and typed {noerror}]-> state2; + untyped_event: state1 -[untyped {noerror}]-> state2; + recover_event: state1 -[recovery {noerror}]-> state2; + repair_event: state1 -[repair1 {noerror}]-> state2; + end component; + **}; + end S; +end Issue2817; diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/MachineEvents.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/MachineEvents.aadl new file mode 100644 index 0000000000..a00d9180c3 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/MachineEvents.aadl @@ -0,0 +1,15 @@ +package MachineEvents +public + annex EMV2 {** + error behavior Machine + use types ErrorLibrary; + events + typed: error event {CommonErrors}; + states + state1: initial state; + state2: state; + transitions + state1 -[typed {noerror}]-> state2; + end behavior; + **}; +end MachineEvents; diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/ValidConditions.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/ValidConditions.aadl new file mode 100644 index 0000000000..06fd794132 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2817/ValidConditions.aadl @@ -0,0 +1,60 @@ +package ValidConditions +public + annex EMV2 {** + error behavior Machine + states + state1: initial state; + state2: state; + end behavior; + **}; + + system S + features + f1: in feature; + f2: in feature; + annex EMV2 {** + use types ErrorLibrary; + use behavior ValidConditions::Machine; + error propagations + f1: in propagation {CommonErrors}; + f2: in propagation {CommonErrors}; + end propagations; + component error behavior + events + typed: error event {CommonErrors}; + untyped: error event; + recovery: recover event; + repair1: repair event; + transitions + incoming: state1 -[f1 {ServiceError} and f2 {noerror}]-> state2; + typed_event: state1 -[typed {ServiceError}]-> state2; + unconstrained_event: state1 -[typed]-> state2; + untyped_event: state1 -[untyped]-> state2; + recover_event: state1 -[recovery]-> state2; + repair_event: state1 -[repair1]-> state2; + end component; + **}; + end S; + + system implementation S.i + subcomponents + child: system Child; + annex EMV2 {** + component error behavior + transitions + outgoing: state1 -[child.f {noerror}]-> state2; + end component; + **}; + end S.i; + + system Child + features + f: out feature; + annex EMV2 {** + use types ErrorLibrary; + error propagations + f: out propagation {CommonErrors}; + end propagations; + **}; + end Child; +end ValidConditions; diff --git a/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2817Test.java b/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2817Test.java new file mode 100644 index 0000000000..2ac595772a --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2817Test.java @@ -0,0 +1,99 @@ +/** + * 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 static org.junit.Assert.assertEquals; + +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.DefaultAnnexLibrary; +import org.osate.aadl2.DefaultAnnexSubclause; +import org.osate.aadl2.SystemType; +import org.osate.aadl2.errormodel.tests.ErrorModelInjectorProvider; +import org.osate.testsupport.AssertHelper; +import org.osate.testsupport.TestHelper; +import org.osate.xtext.aadl2.errormodel.errorModel.AndExpression; +import org.osate.xtext.aadl2.errormodel.errorModel.ErrorModelLibrary; +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 Issue2817Test extends XtextTest { + private static final String PATH = "org.osate.aadl2.errormodel.tests/models/issue2817/"; + private static final String MESSAGE = "The noerror constraint is not permitted on an event."; + + @Inject + private TestHelper testHelper; + + @Inject + private ValidationTestHelper validationHelper; + + @Test + public void rejectsNoerrorOnComponentEvents() throws Exception { + var result = issues = testHelper.testFile(PATH + "Issue2817.aadl"); + var expected = new FluentIssueCollection(result.getResource(), new ArrayList<>(), new ArrayList<>()); + var pkg = (AadlPackage) result.getResource().getContents().getFirst(); + var system = (SystemType) pkg.getPublicSection().getOwnedClassifiers().getFirst(); + var annex = (ErrorModelSubclause) ((DefaultAnnexSubclause) system.getOwnedAnnexSubclauses().getFirst()) + .getParsedAnnexSubclause(); + var conjunction = (AndExpression) annex.getTransitions().get(0).getCondition(); + AssertHelper.assertError(conjunction.getOperands().get(1), result.getIssues(), expected, MESSAGE); + for (int i = 1; i < 4; i++) { + AssertHelper.assertError(annex.getTransitions().get(i).getCondition(), result.getIssues(), expected, MESSAGE); + } + assertEquals(4, result.getIssues().size()); + expected.sizeIs(4); + assertConstraints(expected); + } + + @Test + public void rejectsNoerrorOnBehaviorMachineEvents() throws Exception { + var result = issues = testHelper.testFile(PATH + "MachineEvents.aadl"); + var expected = new FluentIssueCollection(result.getResource(), new ArrayList<>(), new ArrayList<>()); + var pkg = (AadlPackage) result.getResource().getContents().getFirst(); + var library = (ErrorModelLibrary) ((DefaultAnnexLibrary) pkg.getPublicSection().getOwnedAnnexLibraries() + .getFirst()).getParsedAnnexLibrary(); + var condition = library.getBehaviors().getFirst().getTransitions().getFirst().getCondition(); + AssertHelper.assertError(condition, result.getIssues(), expected, MESSAGE); + assertEquals(1, result.getIssues().size()); + expected.sizeIs(1); + assertConstraints(expected); + } + + @Test + public void acceptsEventTypeConstraintsAndNoerrorOnPropagations() throws Exception { + var pkg = testHelper.parseFile(PATH + "ValidConditions.aadl"); + validationHelper.assertNoIssues(pkg); + } +} 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 821454b3d5..df3c42fd96 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 @@ -547,7 +547,9 @@ private void checkConditionElementType(ConditionElement conditionElement) { if (condTS == null) { return; } - if (triggerTS == null && condTS != null) { + if (ep instanceof ErrorBehaviorEvent && EMV2TypeSetUtil.isNoError(condTS)) { + error(conditionElement, "The noerror constraint is not permitted on an event."); + } else if (triggerTS == null && condTS != null) { // it is ok for a state not to have a type set. error(conditionElement, "Condition has type constraint but referenced " + triggerName + " does not."); } else if (!EMV2TypeSetUtil.isNoError(condTS) && !EMV2TypeSetUtil.contains(triggerTS, condTS)) {