diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVStateDoActionWithReferencedActionTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVStateDoActionWithReferencedActionTests.java new file mode 100644 index 000000000..8df1bc7ef --- /dev/null +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVStateDoActionWithReferencedActionTests.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2026 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.syson.application.controllers.diagrams.general.view; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; + +import java.time.Duration; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramEventInput; +import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramRefreshedEventPayload; +import org.eclipse.sirius.components.collaborative.diagrams.dto.ToolVariable; +import org.eclipse.sirius.components.collaborative.diagrams.dto.ToolVariableType; +import org.eclipse.sirius.components.diagrams.Diagram; +import org.eclipse.sirius.components.diagrams.Node; +import org.eclipse.sirius.components.diagrams.ViewModifier; +import org.eclipse.sirius.components.diagrams.tests.navigation.DiagramNavigator; +import org.eclipse.sirius.components.view.emf.diagram.IDiagramIdProvider; +import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState; +import org.eclipse.syson.AbstractIntegrationTests; +import org.eclipse.syson.application.controllers.diagrams.testers.ToolTester; +import org.eclipse.syson.application.data.GeneralViewEmptyTestProjectData; +import org.eclipse.syson.services.diagrams.DiagramDescriptionIdProvider; +import org.eclipse.syson.services.diagrams.api.IGivenDiagramDescription; +import org.eclipse.syson.services.diagrams.api.IGivenDiagramSubscription; +import org.eclipse.syson.standard.diagrams.view.SDVDescriptionNameGenerator; +import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.SysONRepresentationDescriptionIdentifiers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.jdbc.SqlConfig; +import org.springframework.transaction.annotation.Transactional; + +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; + +/** + * Test the creation of a do action with referenced action in the General View diagram.. + * + * @author pcdavid + */ +@Transactional +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class GVStateDoActionWithReferencedActionTests extends AbstractIntegrationTests { + + @Autowired + private IGivenInitialServerState givenInitialServerState; + + @Autowired + private IGivenDiagramSubscription givenDiagramSubscription; + + @Autowired + private IGivenDiagramDescription givenDiagramDescription; + + @Autowired + private IDiagramIdProvider diagramIdProvider; + + @Autowired + private ToolTester toolTester; + + private final IDescriptionNameGenerator descriptionNameGenerator = new SDVDescriptionNameGenerator(); + + private Flux givenSubscriptionToDiagram() { + var diagramEventInput = new DiagramEventInput(UUID.randomUUID(), + GeneralViewEmptyTestProjectData.EDITING_CONTEXT, + GeneralViewEmptyTestProjectData.GraphicalIds.DIAGRAM_ID); + var flux = this.givenDiagramSubscription.subscribe(diagramEventInput); + return flux; + } + + @BeforeEach + public void beforeEach() { + this.givenInitialServerState.initialize(); + } + + @Test + @Sql(scripts = { GeneralViewEmptyTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, + config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED)) + @Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED)) + @DisplayName("GIVEN a General View with a state and action, WHEN invoking do action with referenced action, THEN the PerformActionUsage is visible in the state") + public void checkPerformActionRevealInState() { + var flux = this.givenSubscriptionToDiagram(); + + var diagramDescription = this.givenDiagramDescription.getDiagramDescription(GeneralViewEmptyTestProjectData.EDITING_CONTEXT, + SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID); + + var diagramDescriptionIdProvider = new DiagramDescriptionIdProvider(diagramDescription, this.diagramIdProvider); + var newStateToolId = diagramDescriptionIdProvider.getDiagramCreationToolId("New State"); + assertThat(newStateToolId).as("The tool 'New State' should exist on the diagram").isNotNull(); + var newActionToolId = diagramDescriptionIdProvider.getDiagramCreationToolId("New Action"); + assertThat(newActionToolId).as("The tool 'New Action' should exist on the diagram").isNotNull(); + var newDoActionWithReferencedActionToolId = diagramDescriptionIdProvider.getNodeToolId(this.descriptionNameGenerator.getNodeName(SysmlPackage.eINSTANCE.getStateUsage()), + "New Do Action with referenced Action"); + assertThat(newDoActionWithReferencedActionToolId).as("The tool 'New Do Action with referenced Action' should exist on State").isNotNull(); + + var diagramReference = new AtomicReference(null); + var stateNodeId = new AtomicReference(null); + var actionId = new AtomicReference(null); + + Consumer initialDiagramContentConsumer = payload -> Optional.of(payload) + .map(DiagramRefreshedEventPayload::diagram) + .ifPresentOrElse(diagram -> { + diagramReference.set(diagram); + }, () -> fail("Missing diagram")); + + Runnable createState = () -> this.toolTester.invokeTool(GeneralViewEmptyTestProjectData.EDITING_CONTEXT, diagramReference, newStateToolId); + + Consumer diagramWithStateConsumer = payload -> Optional.of(payload) + .map(DiagramRefreshedEventPayload::diagram) + .ifPresentOrElse(diagram -> { + assertThat(diagram.getNodes()).hasSize(1); + diagram.getNodes().stream() + .filter(node -> node.getTargetObjectLabel().equals("state1")) + .findFirst() + .ifPresentOrElse(node -> stateNodeId.set(node.getId()), () -> fail("Node 'state1' not found")); + }, () -> fail("Missing diagram")); + + Runnable createAction = () -> this.toolTester.invokeTool(GeneralViewEmptyTestProjectData.EDITING_CONTEXT, diagramReference, newActionToolId); + + Consumer diagramWithStateAndActionConsumer = payload -> Optional.of(payload) + .map(DiagramRefreshedEventPayload::diagram) + .ifPresentOrElse(diagram -> { + assertThat(diagram.getNodes()).hasSize(2); + diagram.getNodes().stream() + .filter(node -> node.getTargetObjectLabel().equals("action1")) + .findFirst() + .ifPresentOrElse(node -> actionId.set(node.getTargetObjectId()), () -> fail("Node 'action1' not found")); + }, () -> fail("Missing diagram")); + + Runnable createDoActionWithReference = () -> { + this.toolTester.invokeTool(GeneralViewEmptyTestProjectData.EDITING_CONTEXT, diagramReference.get().getId(), stateNodeId.get(), newDoActionWithReferencedActionToolId, + List.of(new ToolVariable("selectedObject", actionId.get(), ToolVariableType.OBJECT_ID))); + }; + + Consumer diagramWithDoActionConsumer = payload -> Optional.of(payload) + .map(DiagramRefreshedEventPayload::diagram) + .ifPresentOrElse(diagram -> { + assertThat(diagram.getNodes()).hasSize(2); + assertThat(diagram.getEdges()).isEmpty(); + DiagramNavigator navigator = new DiagramNavigator(diagram); + Collection visibleNodes = navigator.findAllNodes().stream().filter(node -> node.getState() == ViewModifier.Normal).toList(); + assertThat(visibleNodes.stream().filter(node -> node.getInsideLabel().getText().equals("actions"))).hasSize(1).allMatch(node -> node.getChildNodes().size() == 1); + assertThat(visibleNodes.stream().filter(node -> node.getInsideLabel().getText().equals("perform actions"))).hasSize(1).allMatch(node -> node.getChildNodes().size() == 1); + assertThat(visibleNodes.stream().filter(node -> node.getInsideLabel().getText().equals("ref do ::> action1"))).hasSize(2); + }, () -> fail("Missing diagram")); + + StepVerifier.create(flux) + .consumeNextWith(initialDiagramContentConsumer) + .then(createState) + .consumeNextWith(diagramWithStateConsumer) + .then(createAction) + .consumeNextWith(diagramWithStateAndActionConsumer) + .then(createDoActionWithReference) + .consumeNextWith(diagramWithDoActionConsumer) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } +} diff --git a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramQueryLabelService.java b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramQueryLabelService.java index fa711911f..1de1afa4a 100644 --- a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramQueryLabelService.java +++ b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramQueryLabelService.java @@ -111,7 +111,6 @@ public String getReferenceSubsettingLabel(Element element) { if (!referenceSubsetting.isIsImplied()) { var referencedFeature = referenceSubsetting.getReferencedFeature(); if (referencedFeature != null) { - label.append(LabelConstants.SPACE); label.append(LabelConstants.REFERENCES); label.append(LabelConstants.SPACE); label.append(this.getDeclaredNameLabel(referencedFeature));