Skip to content
Open
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
3 changes: 2 additions & 1 deletion org.omg.sysml.interactive.tests/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ Require-Bundle: org.omg.sysml.interactive;bundle-version="0.62.0",
org.omg.sysml;bundle-version="0.62.0",
org.eclipse.xtext;bundle-version="2.22.0",
org.omg.kerml.xtext;bundle-version="0.62.0",
org.omg.sysml.xtext;bundle-version="0.62.0"
org.omg.sysml.xtext;bundle-version="0.62.0",
org.omg.kerml.xpect.tests;bundle-version="0.62.0"
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,42 @@

package org.omg.sysml.interactive.tests;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;

import java.util.List;

import org.eclipse.emf.ecore.EClass;
import org.junit.Test;
import org.omg.kerml.xtext.postprocessing.ElementParserPostProcessor;
import org.omg.kerml.xtext.postprocessing.ImportParserPostProcessor;
import org.omg.kerml.xtext.postprocessing.LiteralStringParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.ConnectionUsageParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.ItemUsageParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.OccurrenceUsageParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.PartUsageParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.PortUsageParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.SysMLParserPostProcessorFactory;
import org.omg.kerml.xtext.postprocessing.RedefinitionParserPostProcessor;
import org.omg.sysml.lang.sysml.ConnectionUsage;
import org.omg.sysml.lang.sysml.Element;
import org.omg.sysml.lang.sysml.Feature;
import org.omg.sysml.lang.sysml.FeatureDirectionKind;
import org.omg.sysml.lang.sysml.FeatureMembership;
import org.omg.sysml.lang.sysml.LiteralString;
import org.omg.sysml.lang.sysml.OccurrenceUsage;
import org.omg.sysml.lang.sysml.OwningMembership;
import org.omg.sysml.lang.sysml.PartDefinition;
import org.omg.sysml.lang.sysml.PartUsage;
import org.omg.sysml.lang.sysml.PortDefinition;
import org.omg.sysml.lang.sysml.PortUsage;
import org.omg.sysml.lang.sysml.PortionKind;
import org.omg.sysml.lang.sysml.SysMLFactory;
import org.omg.sysml.lang.sysml.SysMLPackage;
import org.omg.sysml.lang.sysml.Usage;
import org.omg.sysml.util.TypeUtil;
import org.omg.sysml.xtext.postprocessing.ConnectionUsageParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.ItemUsageParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.OccurrenceUsageParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.PartUsageParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.PortUsageParserPostProcessor;
import org.omg.sysml.xtext.postprocessing.SysMLParserPostProcessorFactory;

public class ParserPostProcessorTest extends SysMLInteractiveTest {

Expand Down Expand Up @@ -170,4 +177,83 @@ public void postProcessMakesUsageOutsideFeatureMembershipNonComposite() {

assertFalse(usage.isComposite());
}

@Test
public void standardFactoryUsesTheEcoreCompositeDefault() {
assertFalse(SysMLFactory.eINSTANCE.createUsage().isComposite());
for (EClass eClass : nonCompositeUsageTypes()) {
Usage usage = (Usage)SysMLFactory.eINSTANCE.create(eClass);
assertFalse(eClass.getName(), usage.isComposite());
assertTrue(eClass.getName(), usage.isReference());
}
}

@Test
public void parserAdapterRestoresImplicitConstructorDefaults() {
PartUsage partUsage = (PartUsage)createUsageOwnedByFeatureMembership(SysMLPackage.Literals.PART_USAGE);
postProcess(partUsage);
assertTrue(partUsage.isComposite());

for (EClass eClass : nonCompositeUsageTypes()) {
Usage usage = createUsageOwnedByFeatureMembership(eClass);
postProcess(usage);
assertFalse(eClass.getName(), usage.isComposite());
assertTrue(eClass.getName(), usage.isReference());
}
}

@Test
public void postProcessMakesContextuallyReferentialUsagesNonComposite() {
PartUsage directedUsage = (PartUsage)createUsageOwnedByFeatureMembership(SysMLPackage.Literals.PART_USAGE);
directedUsage.setDirection(FeatureDirectionKind.IN);
postProcess(directedUsage);
assertFalse(directedUsage.isComposite());

PartUsage endUsage = (PartUsage)createUsageOwnedByFeatureMembership(SysMLPackage.Literals.PART_USAGE);
endUsage.setIsEnd(true);
postProcess(endUsage);
assertFalse(endUsage.isComposite());

PartUsage unfeaturedUsage = SysMLFactory.eINSTANCE.createPartUsage();
OwningMembership membership = SysMLFactory.eINSTANCE.createOwningMembership();
membership.setOwnedMemberElement(unfeaturedUsage);
postProcess(unfeaturedUsage);
assertFalse(unfeaturedUsage.isComposite());
}

@Test
public void portUsageIsCompositeOnlyInAPortContext() {
PortUsage portUsage = SysMLFactory.eINSTANCE.createPortUsage();
FeatureMembership membership = SysMLFactory.eINSTANCE.createFeatureMembership();
membership.setOwnedMemberFeature(portUsage);
PortDefinition owner = SysMLFactory.eINSTANCE.createPortDefinition();
owner.getOwnedRelationship().add(membership);
postProcess(portUsage);
assertTrue(portUsage.isComposite());

PortUsage partPortUsage = (PortUsage)createUsageOwnedByFeatureMembership(SysMLPackage.Literals.PORT_USAGE);
postProcess(partPortUsage);
assertFalse(partPortUsage.isComposite());
}

private static List<EClass> nonCompositeUsageTypes() {
return List.of(
SysMLPackage.Literals.ATTRIBUTE_USAGE,
SysMLPackage.Literals.BINDING_CONNECTOR_AS_USAGE,
SysMLPackage.Literals.EVENT_OCCURRENCE_USAGE,
SysMLPackage.Literals.EXHIBIT_STATE_USAGE,
SysMLPackage.Literals.INCLUDE_USE_CASE_USAGE,
SysMLPackage.Literals.PERFORM_ACTION_USAGE,
SysMLPackage.Literals.REFERENCE_USAGE,
SysMLPackage.Literals.SUCCESSION_AS_USAGE);
}

private static Usage createUsageOwnedByFeatureMembership(EClass eClass) {
Usage usage = (Usage)SysMLFactory.eINSTANCE.create(eClass);
FeatureMembership membership = SysMLFactory.eINSTANCE.createFeatureMembership();
membership.setOwnedMemberFeature(usage);
PartDefinition owner = SysMLFactory.eINSTANCE.createPartDefinition();
owner.getOwnedRelationship().add(membership);
return usage;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*******************************************************************************
* SysML 2 Pilot Implementation
* Copyright (c) 2026 Obeo
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/

package org.omg.sysml.interactive.tests;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;

import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.resource.XtextResourceSet;
import org.junit.BeforeClass;
import org.junit.Test;
import org.omg.kerml.xpect.KerMLXtextTests;
import org.omg.sysml.lang.sysml.SysMLFactory;
import org.omg.sysml.lang.sysml.SysMLPackage;
import org.omg.sysml.lang.sysml.Usage;
import org.omg.sysml.xtext.SysMLStandaloneSetup;

import com.google.inject.Injector;

public class UsageParsingTest {

private static Injector injector;

@BeforeClass
public static void setUp() {
KerMLXtextTests.setup();
injector = new SysMLStandaloneSetup().createInjectorAndDoEMFRegistration();
SysMLPackage.eINSTANCE.eClass();
}

@Test
public void parserUsesSyntaxNodesToApplyCompositeDefaults() throws IOException {
XtextResource resource = parse("""
part def P {
part implicitComposite;
ref part explicitReference;
in part directed;
attribute nonCompositeType;
}
action def A {
merge explicitComposite;
}
""");

Usage implicitComposite = findUsage(resource, "implicitComposite");
assertTrue(NodeModelUtils.findNodesForFeature(
implicitComposite, SysMLPackage.Literals.FEATURE__IS_COMPOSITE).isEmpty());
assertTrue(NodeModelUtils.findNodesForFeature(
implicitComposite, SysMLPackage.Literals.USAGE__IS_REFERENCE).isEmpty());
assertTrue(implicitComposite.isComposite());

Usage explicitReference = findUsage(resource, "explicitReference");
assertFalse(NodeModelUtils.findNodesForFeature(
explicitReference, SysMLPackage.Literals.USAGE__IS_REFERENCE).isEmpty());
assertTrue(explicitReference.isReference());

Usage explicitComposite = findUsage(resource, "explicitComposite");
assertFalse(NodeModelUtils.findNodesForFeature(
explicitComposite, SysMLPackage.Literals.FEATURE__IS_COMPOSITE).isEmpty());
assertTrue(explicitComposite.isComposite());

assertTrue(findUsage(resource, "directed").isReference());
assertTrue(findUsage(resource, "nonCompositeType").isReference());
}

@Test
public void compositeValuesSurviveXmiRoundTrips() throws IOException {
assertXmiRoundTrip(false);
assertXmiRoundTrip(true);

Usage usage = SysMLFactory.eINSTANCE.createUsage();
usage.setIsComposite(true);
usage.eUnset(SysMLPackage.Literals.FEATURE__IS_COMPOSITE);
Usage loaded = xmiRoundTrip(usage);
assertFalse(loaded.isComposite());
assertTrue(loaded.isReference());
}

private static XtextResource parse(String text) throws IOException {
XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);
XtextResource resource = (XtextResource)resourceSet.createResource(URI.createURI("memory:/usage.sysml"));
resource.load(new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)), Map.of());
EcoreUtil.resolveAll(resource);
assertTrue(resource.getErrors().toString(), resource.getErrors().isEmpty());
return resource;
}

private static Usage findUsage(Resource resource, String name) {
TreeIterator<EObject> iterator = resource.getAllContents();
while (iterator.hasNext()) {
EObject object = iterator.next();
if (object instanceof Usage usage && name.equals(usage.getDeclaredName())) {
return usage;
}
}
fail("Usage not found: " + name);
return null;
}

private static void assertXmiRoundTrip(boolean isComposite) throws IOException {
Usage usage = SysMLFactory.eINSTANCE.createUsage();
usage.setIsComposite(isComposite);
Usage loaded = xmiRoundTrip(usage);
if (isComposite) {
assertTrue(loaded.isComposite());
assertFalse(loaded.isReference());
} else {
assertFalse(loaded.isComposite());
assertTrue(loaded.isReference());
}
}

private static Usage xmiRoundTrip(Usage usage) throws IOException {
URI uri = URI.createURI("memory:/usage.xmi");
Resource savedResource = new XMIResourceImpl(uri);
savedResource.getContents().add(usage);
ByteArrayOutputStream output = new ByteArrayOutputStream();
savedResource.save(output, Map.of());

Resource loadedResource = new XMIResourceImpl(uri);
loadedResource.load(new ByteArrayInputStream(output.toByteArray()), Map.of());
return (Usage)loadedResource.getContents().get(0);
}
}
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,10 @@ public class AttributeUsageImpl extends UsageImpl implements AttributeUsage {
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
* @generated
*/
protected AttributeUsageImpl() {
super();
isComposite = false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ public class BindingConnectorAsUsageImpl extends ConnectorAsUsageImpl implements
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
* @generated
*/
protected BindingConnectorAsUsageImpl() {
super();
isComposite = false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ public class EventOccurrenceUsageImpl extends OccurrenceUsageImpl implements Eve
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
* @generated
*/
protected EventOccurrenceUsageImpl() {
super();
isComposite = false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,10 @@ public class ExhibitStateUsageImpl extends StateUsageImpl implements ExhibitStat
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
* @generated
*/
protected ExhibitStateUsageImpl() {
super();
isComposite = false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,10 @@ public class IncludeUseCaseUsageImpl extends UseCaseUsageImpl implements Include
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
* @generated
*/
protected IncludeUseCaseUsageImpl() {
super();
isComposite = false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ public class PerformActionUsageImpl extends ActionUsageImpl implements PerformAc
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
* @generated
*/
protected PerformActionUsageImpl() {
super();
isComposite = false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ public class ReferenceUsageImpl extends UsageImpl implements ReferenceUsage {
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
* @generated
*/
protected ReferenceUsageImpl() {
super();
isComposite = false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ public class SuccessionAsUsageImpl extends ConnectorAsUsageImpl implements Succe
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
* @generated
*/
protected SuccessionAsUsageImpl() {
super();
isComposite = false;
}

/**
Expand Down
Loading
Loading