Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/org.osate.ui.tests/models/issue3235/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/.aadlbin-gen/
/instances/
18 changes: 18 additions & 0 deletions core/org.osate.ui.tests/models/issue3235/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>issue3235</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.osate.core.aadlnature</nature>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
</natures>
</projectDescription>
27 changes: 27 additions & 0 deletions core/org.osate.ui.tests/models/issue3235/Issue3235.aadl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package Issue3235
public
with Issue3235_Properties;

system Plain
end Plain;

system implementation Plain.Impl
end Plain.Impl;

system Container
end Container;

system implementation Container.Impl
subcomponents
first_child: system Plain.Impl;
second_child: system Plain.Impl;
properties
Issue3235_Properties::Flag_Property => true applies to first_child, second_child;
Issue3235_Properties::Record_Property => [
First => 1;
Second => 2;
] applies to first_child, second_child;
Issue3235_Properties::List_Property => (1, 2) applies to first_child, second_child;
Issue3235_Properties::Range_Property => 1 .. 9 delta 2 applies to first_child, second_child;
end Container.Impl;
end Issue3235;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
property set Issue3235_Properties is
Flag_Property: aadlboolean applies to (system);
Record_Property: record (
First: aadlinteger;
Second: aadlinteger;
) applies to (system);
List_Property: list of aadlinteger applies to (system);
Range_Property: range of aadlinteger applies to (system);
end Issue3235_Properties;
7 changes: 7 additions & 0 deletions core/org.osate.ui.tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@
<id>org.osate.core.feature</id>
<versionRange>0.0.0</versionRange>
</requirement>
<!-- Property lookup loads contributed EMV2 libraries. The UI
bundle registers the resource service provider used by their parser. -->
<requirement>
<type>eclipse-plugin</type>
<id>org.osate.xtext.aadl2.errormodel.ui</id>
<versionRange>0.0.0</versionRange>
</requirement>
<!-- The graphical editor, for the wizard test that creates a
package with a diagram. It contributes the AgeEditor, which is built on
GEF and JavaFX, so the JavaFX runtime is needed as well. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,10 @@ public void testSharedLocalContainedPropertyOfASubcomponent() {

/*
* The association applies to more than one subcomponent, so there is no single association to open for this one.
* Remove is offered because the check behind it does not distinguish a shared association from one that applies
* to this subcomponent alone; this is the current behavior of the view, not necessarily the intended one.
* It must be made local or local contained before it can be removed without affecting the other subcomponents.
*/
assertContextMenuEnablement(new String[] { PROPERTY_SET, "Flag_Property" },
List.of(OPEN_PROPERTY_DEFINITION, MAKE_LOCAL, MAKE_LOCAL_CONTAINED, REMOVE));
List.of(OPEN_PROPERTY_DEFINITION, MAKE_LOCAL, MAKE_LOCAL_CONTAINED));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/**
* 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.ui.tests.propertyview;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.LOCAL;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.LOCAL_CONTAINED;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.MAKE_LOCAL;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.MAKE_LOCAL_CONTAINED;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.REMOVE;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.SHARED_LOCAL_CONTAINED;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.UNDEFINED;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.VALUE_COLUMN;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.assertStatus;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.assertValue;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.clickContextMenu;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.contextMenuEnablement;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.item;
import static org.osate.ui.tests.propertyview.util.AadlPropertyViewBot.showUndefinedProperties;
import static org.osate.ui.tests.propertyview.util.WorkbenchTestUtil.assertNoErrorsInProject;
import static org.osate.ui.tests.propertyview.util.WorkbenchTestUtil.closeAllEditors;
import static org.osate.ui.tests.propertyview.util.WorkbenchTestUtil.closeEditorWithoutSaving;
import static org.osate.ui.tests.propertyview.util.WorkbenchTestUtil.deleteProject;
import static org.osate.ui.tests.propertyview.util.WorkbenchTestUtil.editorText;
import static org.osate.ui.tests.propertyview.util.WorkbenchTestUtil.importModelProject;
import static org.osate.ui.tests.propertyview.util.WorkbenchTestUtil.openEditor;
import static org.osate.ui.tests.propertyview.util.WorkbenchTestUtil.prepareWorkbench;
import static org.osate.ui.tests.propertyview.util.WorkbenchTestUtil.selectInEditor;

import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.swt.SWT;
import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable;
import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.osate.ui.tests.propertyview.util.AadlPropertyViewBot;

/**
* A shared contained association must not be editable or removable from one of its targets.
*/
@RunWith(SWTBotJunit4ClassRunner.class)
public class Issue3235Test {
private static final String PROJECT = "issue3235";
private static final String MODEL_FILE = "Issue3235.aadl";
private static final String PROPERTY_SET = "Issue3235_Properties";
private static final String[] FLAG_PATH = { PROPERTY_SET, "Flag_Property" };
private static IProject project;

@BeforeClass
public static void importModel() {
prepareWorkbench();
project = importModelProject(PROJECT);
assertNoErrorsInProject(project);
AadlPropertyViewBot.reopen();
}

@AfterClass
public static void discardModel() {
closeAllEditors();
AadlPropertyViewBot.close();
deleteProject(PROJECT);
}

@Before
public void openPristineModel() {
closeEditorWithoutSaving(MODEL_FILE);
openEditor(project, MODEL_FILE);
selectInEditor(MODEL_FILE, "implementation Plain.Impl");
AadlPropertyViewBot.tree();
AadlPropertyViewBot.resetFilters();
selectChild("second_child");
showUndefinedProperties(true);
}

@Test
public void testRemoveDoesNotDeleteOtherChildValue() {
assertValue("true", FLAG_PATH);
var originalText = editorText(MODEL_FILE);
selectChild("first_child");

// Exercise the destructive action if the bug makes it available, then check the unselected child first.
boolean removeEnabled = contextMenuEnablement(FLAG_PATH, List.of(REMOVE)).get(REMOVE);
if (removeEnabled) {
clickContextMenu(FLAG_PATH, REMOVE);
assertStatus(UNDEFINED, FLAG_PATH);
}
selectChild("second_child");
assertValue("true", FLAG_PATH);
assertStatus(SHARED_LOCAL_CONTAINED, FLAG_PATH);
assertEquals("The shared association must remain unchanged", originalText, editorText(MODEL_FILE));
assertFalse("Remove must be disabled for a shared association", removeEnabled);
}

@Test
public void testSharedScalarIsReadOnlyForBothChildren() {
for (var child : List.of("first_child", "second_child")) {
selectChild(child);
assertValue("true", FLAG_PATH);
assertStatus(SHARED_LOCAL_CONTAINED, FLAG_PATH);
assertReadOnly(FLAG_PATH);
}
}

@Test
public void testSharedRecordFieldIsReadOnly() {
selectChild("first_child");
assertValue("1", PROPERTY_SET, "Record_Property", "First");
assertStatus(SHARED_LOCAL_CONTAINED, PROPERTY_SET, "Record_Property", "First");
assertReadOnly(PROPERTY_SET, "Record_Property", "First");
}

@Test
public void testSharedListElementIsReadOnly() {
selectChild("first_child");
assertValue("1", PROPERTY_SET, "List_Property", "# 0");
assertReadOnly(PROPERTY_SET, "List_Property", "# 0");
}

@Test
public void testSharedRangeDeltaIsReadOnly() {
selectChild("first_child");
assertValue("2", PROPERTY_SET, "Range_Property", "delta");
assertReadOnly(PROPERTY_SET, "Range_Property", "delta");
}

@Test
public void testMakeLocalThenRemovePreservesOtherChild() {
makeLocalThenRemove(MAKE_LOCAL, LOCAL);
}

@Test
public void testMakeLocalContainedThenRemovePreservesOtherChild() {
makeLocalThenRemove(MAKE_LOCAL_CONTAINED, LOCAL_CONTAINED);
}

private static void makeLocalThenRemove(String action, String expectedStatus) {
selectChild("first_child");
clickContextMenu(FLAG_PATH, action);
assertStatus(expectedStatus, FLAG_PATH);
assertValue("true", FLAG_PATH);
clickContextMenu(FLAG_PATH, REMOVE);
assertStatus(UNDEFINED, FLAG_PATH);
assertValue("", FLAG_PATH);

selectChild("second_child");
assertStatus(LOCAL_CONTAINED, FLAG_PATH);
assertValue("true", FLAG_PATH);
}

private static void selectChild(String child) {
// Force a selection change even when the previous selection is the same child.
selectInEditor(MODEL_FILE, "public");
AadlPropertyViewBot.assertNoPropertiesShown();
selectInEditor(MODEL_FILE, child);
AadlPropertyViewBot.tree();
}

private static void assertReadOnly(String... path) {
SWTBotTreeItem treeItem = item(path);
boolean greyedOut = UIThreadRunnable.syncExec(() -> treeItem.widget.getDisplay()
.getSystemColor(SWT.COLOR_DARK_GRAY)
.equals(treeItem.widget.getForeground(VALUE_COLUMN)));
assertTrue("A shared value must be greyed out", greyedOut);
assertFalse("Remove must be disabled for a shared value",
contextMenuEnablement(path, List.of(REMOVE)).get(REMOVE));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1187,15 +1187,7 @@ PropertyStatus getPropertyStatus(URI propertySetURI, URI propertyURI) {
var associationURI = cachedPropertyAssociations.get(propertySetURI).get(propertyURI);
if (associationURI != null) {
var association = (PropertyAssociation) resourceSet.getEObject(associationURI, true);
var inputElement = resourceSet.getEObject(getInput(), true);
if (Objects.equals(inputElement, association.getOwner())) {
return PropertyStatus.LOCAL;
}
if (associationAppliesTo(association, inputElement)) {
return association.getAppliesTos().size() > 1 ? PropertyStatus.LOCAL_SHARED
: PropertyStatus.LOCAL_CONTAINED;
}
return PropertyStatus.INHERITED;
return getPropertyStatusNeverUndefined(resourceSet, association);
}
return ((Property) resourceSet.getEObject(propertyURI, true)).getDefaultValue() != null
? PropertyStatus.DEFAULT
Expand All @@ -1217,8 +1209,11 @@ PropertyStatus getPropertyStatusNeverUndefined(ResourceSet resourceSet, Property
if (Objects.equals(inputElement, association.getOwner())) {
return PropertyStatus.LOCAL;
}
return associationAppliesTo(association, inputElement) ? PropertyStatus.LOCAL_CONTAINED
: PropertyStatus.INHERITED;
if (associationAppliesTo(association, inputElement)) {
return association.getAppliesTos().size() > 1 ? PropertyStatus.LOCAL_SHARED
: PropertyStatus.LOCAL_CONTAINED;
}
return PropertyStatus.INHERITED;
}

private static boolean associationAppliesTo(PropertyAssociation association, EObject inputElement) {
Expand Down