Skip to content

Commit 5dd719c

Browse files
gcoutableAxelRICHARD
authored andcommitted
[2122] Improve subject creation tool
Bug: #2122 Signed-off-by: Guillaume Coutable <guillaume.coutable@obeo.fr>
1 parent a1926e1 commit 5dd719c

5 files changed

Lines changed: 331 additions & 48 deletions

File tree

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Stakeholders are by default represented with a dedicated graphical node connecte
4444
- [releng] Fix the license and URL of our maven modules in the SBOM
4545
- https://github.com/eclipse-syson/syson/issues/2108[#2108] [diagrams] Leverage the latest change of the selection dialog to allow creating an `Actor` graphical node without specialization.
4646
- https://github.com/eclipse-syson/syson/issues/2111[#2111] [diagrams] Leverage the latest change of the selection dialog to allow creating a `Stakeholder` graphical node without specialization.
47+
- https://github.com/eclipse-syson/syson/issues/2122[#2122] [diagrams] Leverage the latest change of the selection dialog to allow creating a `Subject` graphical node without specialization.
4748

4849
=== New features
4950

backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeAnalysisCreationTests.java

Lines changed: 102 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,9 @@
1515
import static org.assertj.core.api.Assertions.assertThat;
1616
import static org.assertj.core.api.InstanceOfAssertFactories.type;
1717
import static org.eclipse.sirius.components.diagrams.tests.DiagramEventPayloadConsumer.assertRefreshedDiagramThat;
18-
import static org.junit.jupiter.api.Assertions.assertFalse;
1918

2019
import java.time.Duration;
21-
import java.util.ArrayList;
2220
import java.util.List;
23-
import java.util.Objects;
24-
import java.util.Optional;
2521
import java.util.UUID;
2622
import java.util.concurrent.atomic.AtomicReference;
2723
import java.util.function.Consumer;
@@ -32,15 +28,12 @@
3228
import org.eclipse.emf.ecore.EReference;
3329
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramEventInput;
3430
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramRefreshedEventPayload;
35-
import org.eclipse.sirius.components.collaborative.diagrams.dto.ToolVariable;
36-
import org.eclipse.sirius.components.collaborative.diagrams.dto.ToolVariableType;
3731
import org.eclipse.sirius.components.core.api.IObjectSearchService;
3832
import org.eclipse.sirius.components.diagrams.Diagram;
3933
import org.eclipse.sirius.components.view.emf.diagram.IDiagramIdProvider;
4034
import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState;
4135
import org.eclipse.syson.AbstractIntegrationTests;
4236
import org.eclipse.syson.GivenSysONServer;
43-
import org.eclipse.syson.application.controller.editingcontext.checkers.ISemanticChecker;
4437
import org.eclipse.syson.application.controller.editingcontext.checkers.SemanticCheckerService;
4538
import org.eclipse.syson.application.controllers.diagrams.checkers.CheckBorderNode;
4639
import org.eclipse.syson.application.controllers.diagrams.checkers.CheckDiagramElementCount;
@@ -63,7 +56,6 @@
6356
import org.eclipse.syson.sysml.Subsetting;
6457
import org.eclipse.syson.sysml.SysmlPackage;
6558
import org.eclipse.syson.sysml.Type;
66-
import org.eclipse.syson.sysml.helper.EMFUtils;
6759
import org.eclipse.syson.util.IDescriptionNameGenerator;
6860
import org.eclipse.syson.util.SysONRepresentationDescriptionIdentifiers;
6961
import org.junit.jupiter.api.BeforeEach;
@@ -85,6 +77,7 @@
8577
* @author arichard
8678
*/
8779
@Transactional
80+
@SuppressWarnings("checkstyle:MultipleStringLiterals")
8881
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
8982
public class GVSubNodeAnalysisCreationTests extends AbstractIntegrationTests {
9083

@@ -480,30 +473,48 @@ public void createUseCaseDefinitionChildNodes(EClass childEClass, String compart
480473
.verify(Duration.ofSeconds(10));
481474
}
482475

476+
@DisplayName("GIVEN a Case, WHEN creating a new Subject selecting a Part, THEN the Subject subsetted by the Part is created in the Case")
483477
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
484478
@Test
485479
public void createNewUsageSubjectInCaseUsage() {
486480
this.createSubjectWithSubsettingInCaseUsage(SysmlPackage.eINSTANCE.getCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.CASE_USAGE_ID, CASE);
487481
}
488482

483+
@DisplayName("GIVEN a UseCase, WHEN creating a new Subject selecting a Part, THEN the Subject subsetted by the Part is created in the UseCase")
489484
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
490485
@Test
491486
public void createNewUsageSubjectInUseCaseUsage() {
492487
this.createSubjectWithSubsettingInCaseUsage(SysmlPackage.eINSTANCE.getUseCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.USE_CASE_USAGE_ID, USE_CASE);
493488
}
494489

490+
@DisplayName("GIVEN a Case, WHEN creating a new Subject selecting a PartDefinition, THEN the Subject typed by the PartDefinition is created in the Case")
495491
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
496492
@Test
497493
public void createNewDefinitionSubjectInCaseUsage() {
498494
this.createSubjectWithFeatureTypingInCaseUsage(SysmlPackage.eINSTANCE.getCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.CASE_USAGE_ID, CASE);
499495
}
500496

497+
@DisplayName("GIVEN a UseCase, WHEN creating a new Subject selecting a PartDefinition, THEN the Subject typed by the PartDefinition is created in the UseCase")
501498
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
502499
@Test
503500
public void createNewDefinitionSubjectInUseCaseUsage() {
504501
this.createSubjectWithFeatureTypingInCaseUsage(SysmlPackage.eINSTANCE.getUseCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.USE_CASE_USAGE_ID, USE_CASE);
505502
}
506503

504+
@DisplayName("GIVEN a Case, WHEN creating a new Subject without selection, THEN the Subject without specialization is created in the Case")
505+
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
506+
@Test
507+
public void createNewSubjectWithoutSpecializationInCaseUsage() {
508+
this.createSubjectWithoutSpecializationInCaseUsage(SysmlPackage.eINSTANCE.getCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.CASE_USAGE_ID, CASE);
509+
}
510+
511+
@DisplayName("GIVEN a UseCase, WHEN creating a new Subject without selection, THEN the Subject without specialization is created in the UseCase")
512+
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
513+
@Test
514+
public void createNewSubjectWithoutSpecializationInUseCaseUsage() {
515+
this.createSubjectWithoutSpecializationInCaseUsage(SysmlPackage.eINSTANCE.getUseCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.USE_CASE_USAGE_ID, USE_CASE);
516+
}
517+
507518
@DisplayName("GIVEN a Case, WHEN creating a new Actor selecting a Part, THEN the Actor subsetted by the Part is created in the Case")
508519
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
509520
@Test
@@ -559,11 +570,8 @@ private void createSubjectWithSubsettingInCaseUsage(EClass caseUsageSubclass, St
559570
EClass childEClass = SysmlPackage.eINSTANCE.getReferenceUsage();
560571
String creationToolName = "New Subject";
561572
EReference containmentReference = SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter();
562-
List<ToolVariable> variables = new ArrayList<>();
563-
String existingPartId = "2c5fe5a5-18fe-40f4-ab66-a2d91ab7df6a";
564-
variables.add(new ToolVariable("selectedObject", existingPartId, ToolVariableType.OBJECT_ID));
565573

566-
Runnable createNodeRunnable = this.creationTestsService.createNode(diagramDescriptionIdProvider, diagram, caseUsageSubclass, targetObjectId, creationToolName, variables);
574+
Runnable createNodeRunnable = this.creationTestsService.createNodeWithSelectionDialogWithSingleSelection(diagramDescriptionIdProvider, diagram, caseUsageSubclass, targetObjectId, creationToolName, GeneralViewWithTopNodesTestProjectData.SemanticIds.PART_USAGE_ID);
567575

568576
Consumer<Object> diagramCheck = assertRefreshedDiagramThat(newDiagram -> {
569577
var initialDiagram = diagram.get();
@@ -587,28 +595,24 @@ private void createSubjectWithSubsettingInCaseUsage(EClass caseUsageSubclass, St
587595
.check(initialDiagram, newDiagram);
588596
});
589597

590-
ISemanticChecker semanticChecker = (editingContext) -> {
591-
Object semanticRootObject = this.objectSearchService.getObject(editingContext, GeneralViewWithTopNodesTestProjectData.SemanticIds.PACKAGE_1_ID).orElse(null);
592-
assertThat(semanticRootObject).isInstanceOf(Element.class);
593-
Element semanticRootElement = (Element) semanticRootObject;
594-
Optional<ReferenceUsage> optParentElement = EMFUtils.allContainedObjectOfType(semanticRootElement, ReferenceUsage.class)
595-
.filter(element -> Objects.equals(element.getName(), "subject"))
596-
.findFirst();
597-
assertThat(optParentElement).isPresent();
598-
var referenceUsage = optParentElement.get();
599-
EList<Subsetting> subjectSubsets = referenceUsage.getOwnedSubsetting();
600-
assertFalse(subjectSubsets.isEmpty());
601-
assertThat(subjectSubsets.get(0).getSubsettedFeature().getName()).isEqualTo("part");
598+
Consumer<Object> additionalCheck = referencedObject -> {
599+
assertThat(referencedObject)
600+
.isInstanceOf(ReferenceUsage.class)
601+
.asInstanceOf(type(ReferenceUsage.class))
602+
.satisfies(referenceUsage -> {
603+
EList<Subsetting> subjectSubsets = referenceUsage.getOwnedSubsetting();
604+
assertThat(subjectSubsets).isNotEmpty();
605+
assertThat(subjectSubsets.get(0).getSubsettedFeature().getName()).isEqualTo("part");
606+
});
602607
};
603-
Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker(parentLabel, containmentReference, childEClass));
604-
Runnable semanticCheck2 = this.semanticCheckerService.checkEditingContext(semanticChecker);
608+
609+
Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker(parentLabel, containmentReference, childEClass, additionalCheck));
605610

606611
StepVerifier.create(flux)
607612
.consumeNextWith(initialDiagramContentConsumer)
608613
.then(createNodeRunnable)
609614
.consumeNextWith(diagramCheck)
610615
.then(semanticCheck)
611-
.then(semanticCheck2)
612616
.thenCancel()
613617
.verify(Duration.ofSeconds(10));
614618
}
@@ -626,11 +630,8 @@ private void createSubjectWithFeatureTypingInCaseUsage(EClass caseUsageSubclass,
626630
EClass childEClass = SysmlPackage.eINSTANCE.getReferenceUsage();
627631
String creationToolName = "New Subject";
628632
EReference containmentReference = SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter();
629-
List<ToolVariable> variables = new ArrayList<>();
630-
String existingPartDefId = GeneralViewWithTopNodesTestProjectData.SemanticIds.PART_DEFINITION_ID;
631-
variables.add(new ToolVariable("selectedObject", existingPartDefId, ToolVariableType.OBJECT_ID));
632633

633-
Runnable createNodeRunnable = this.creationTestsService.createNode(diagramDescriptionIdProvider, diagram, caseUsageSubclass, targetObjectId, creationToolName, variables);
634+
Runnable createNodeRunnable = this.creationTestsService.createNodeWithSelectionDialogWithSingleSelection(diagramDescriptionIdProvider, diagram, caseUsageSubclass, targetObjectId, creationToolName, GeneralViewWithTopNodesTestProjectData.SemanticIds.PART_DEFINITION_ID);
634635

635636
Consumer<Object> diagramCheck = assertRefreshedDiagramThat(newDiagram -> {
636637
var initialDiagram = diagram.get();
@@ -654,28 +655,83 @@ private void createSubjectWithFeatureTypingInCaseUsage(EClass caseUsageSubclass,
654655
.check(initialDiagram, newDiagram);
655656
});
656657

657-
ISemanticChecker semanticChecker = (editingContext) -> {
658-
Object semanticRootObject = this.objectSearchService.getObject(editingContext, GeneralViewWithTopNodesTestProjectData.SemanticIds.PACKAGE_1_ID).orElse(null);
659-
assertThat(semanticRootObject).isInstanceOf(Element.class);
660-
Element semanticRootElement = (Element) semanticRootObject;
661-
Optional<ReferenceUsage> optParentElement = EMFUtils.allContainedObjectOfType(semanticRootElement, ReferenceUsage.class)
662-
.filter(element -> Objects.equals(element.getName(), "subject"))
663-
.findFirst();
664-
assertThat(optParentElement).isPresent();
665-
var referenceUsage = optParentElement.get();
666-
EList<Type> types = referenceUsage.getType();
667-
assertFalse(types.isEmpty());
668-
assertThat(types.get(0).getName()).isEqualTo("PartDefinition");
658+
Consumer<Object> additionalCheck = referencedObject -> {
659+
assertThat(referencedObject)
660+
.isInstanceOf(ReferenceUsage.class)
661+
.asInstanceOf(type(ReferenceUsage.class))
662+
.satisfies(referenceUsage -> {
663+
EList<Type> types = referenceUsage.getType();
664+
assertThat(types).isNotEmpty();
665+
assertThat(types.get(0).getName()).isEqualTo("PartDefinition");
666+
});
669667
};
670-
Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker(parentLabel, containmentReference, childEClass));
671-
Runnable semanticCheck2 = this.semanticCheckerService.checkEditingContext(semanticChecker);
668+
669+
Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker(parentLabel, containmentReference, childEClass, additionalCheck));
670+
671+
StepVerifier.create(flux)
672+
.consumeNextWith(initialDiagramContentConsumer)
673+
.then(createNodeRunnable)
674+
.consumeNextWith(diagramCheck)
675+
.then(semanticCheck)
676+
.thenCancel()
677+
.verify(Duration.ofSeconds(10));
678+
}
679+
680+
private void createSubjectWithoutSpecializationInCaseUsage(EClass caseUsageSubclass, String targetObjectId, String parentLabel) {
681+
var flux = this.givenSubscriptionToDiagram();
682+
683+
AtomicReference<Diagram> diagram = new AtomicReference<>();
684+
Consumer<Object> initialDiagramContentConsumer = assertRefreshedDiagramThat(diagram::set);
685+
686+
var diagramDescription = this.givenDiagramDescription.getDiagramDescription(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID,
687+
SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID);
688+
var diagramDescriptionIdProvider = new DiagramDescriptionIdProvider(diagramDescription, this.diagramIdProvider);
689+
690+
EClass childEClass = SysmlPackage.eINSTANCE.getReferenceUsage();
691+
String creationToolName = "New Subject";
692+
EReference containmentReference = SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter();
693+
694+
Runnable createNodeRunnable = this.creationTestsService.createNodeWithSelectionDialogWithoutSelectionProvided(diagramDescriptionIdProvider, diagram, caseUsageSubclass, targetObjectId, creationToolName);
695+
696+
Consumer<Object> diagramCheck = assertRefreshedDiagramThat(newDiagram -> {
697+
var initialDiagram = diagram.get();
698+
int createdNodesExpectedCount = 2;
699+
new CheckDiagramElementCount(this.diagramComparator)
700+
.hasNewNodeCount(createdNodesExpectedCount)
701+
.hasNewEdgeCount(1)
702+
.check(initialDiagram, newDiagram);
703+
// Only the node inside the compartment is visible
704+
// The "sibling" node is hidden
705+
new CheckDiagramElementCount(this.diagramComparator)
706+
.hasNewNodeCount(1)
707+
.hasNewEdgeCount(0)
708+
.check(initialDiagram, newDiagram, true);
709+
String listNodeDescription = this.descriptionNameGenerator.getCompartmentItemName(SysmlPackage.eINSTANCE.getCaseUsage(), containmentReference);
710+
new CheckNodeInCompartment(diagramDescriptionIdProvider, this.diagramComparator)
711+
.withTargetObjectId(targetObjectId)
712+
.withCompartmentName("subject")
713+
.hasNodeDescriptionName(listNodeDescription)
714+
.hasCompartmentCount(0)
715+
.check(initialDiagram, newDiagram);
716+
});
717+
718+
Consumer<Object> additionalCheck = referencedObject -> {
719+
assertThat(referencedObject)
720+
.isInstanceOf(ReferenceUsage.class)
721+
.asInstanceOf(type(ReferenceUsage.class))
722+
.satisfies(referenceUsage -> {
723+
assertThat(referenceUsage.getOwnedSpecialization()).allMatch(Specialization::isIsImplied);
724+
assertThat(referenceUsage.getType()).isEmpty();
725+
});
726+
};
727+
728+
Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker(parentLabel, containmentReference, childEClass, additionalCheck));
672729

673730
StepVerifier.create(flux)
674731
.consumeNextWith(initialDiagramContentConsumer)
675732
.then(createNodeRunnable)
676733
.consumeNextWith(diagramCheck)
677734
.then(semanticCheck)
678-
.then(semanticCheck2)
679735
.thenCancel()
680736
.verify(Duration.ofSeconds(10));
681737
}

0 commit comments

Comments
 (0)