Skip to content

Commit fa03ee3

Browse files
committed
[2122] Improve subject creation tool using the latest selection dialog changes
Bug: #2122 Signed-off-by: Guillaume Coutable <guillaume.coutable@obeo.fr>
1 parent ec39d4c commit fa03ee3

7 files changed

Lines changed: 363 additions & 49 deletions

File tree

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ As a result, the following GraphQL mutations have been removed `exposeRequiremen
3232

3333
=== Improvements
3434

35+
- 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.
3536

3637
=== New features
3738

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

Lines changed: 105 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package org.eclipse.syson.application.controllers.diagrams.general.view;
1414

1515
import static org.assertj.core.api.Assertions.assertThat;
16+
import static org.assertj.core.api.InstanceOfAssertFactories.type;
1617
import static org.eclipse.sirius.components.diagrams.tests.DiagramEventPayloadConsumer.assertRefreshedDiagramThat;
1718
import static org.junit.jupiter.api.Assertions.assertFalse;
1819

@@ -58,13 +59,15 @@
5859
import org.eclipse.syson.sysml.Element;
5960
import org.eclipse.syson.sysml.PartUsage;
6061
import org.eclipse.syson.sysml.ReferenceUsage;
62+
import org.eclipse.syson.sysml.Specialization;
6163
import org.eclipse.syson.sysml.Subsetting;
6264
import org.eclipse.syson.sysml.SysmlPackage;
6365
import org.eclipse.syson.sysml.Type;
6466
import org.eclipse.syson.sysml.helper.EMFUtils;
6567
import org.eclipse.syson.util.IDescriptionNameGenerator;
6668
import org.eclipse.syson.util.SysONRepresentationDescriptionIdentifiers;
6769
import org.junit.jupiter.api.BeforeEach;
70+
import org.junit.jupiter.api.DisplayName;
6871
import org.junit.jupiter.api.Test;
6972
import org.junit.jupiter.params.ParameterizedTest;
7073
import org.junit.jupiter.params.provider.Arguments;
@@ -82,6 +85,7 @@
8285
* @author arichard
8386
*/
8487
@Transactional
88+
@SuppressWarnings("checkstyle:MultipleStringLiterals")
8589
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
8690
public class GVSubNodeAnalysisCreationTests extends AbstractIntegrationTests {
8791

@@ -477,30 +481,48 @@ public void createUseCaseDefinitionChildNodes(EClass childEClass, String compart
477481
.verify(Duration.ofSeconds(10));
478482
}
479483

484+
@DisplayName("GIVEN a Case, WHEN creating a new Subject selecting a Part, THEN the Subject subsetted by the Part is created in the Case")
480485
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
481486
@Test
482487
public void createNewUsageSubjectInCaseUsage() {
483488
this.createSubjectWithSubsettingInCaseUsage(SysmlPackage.eINSTANCE.getCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.CASE_USAGE_ID, CASE);
484489
}
485490

491+
@DisplayName("GIVEN a UseCase, WHEN creating a new Subject selecting a Part, THEN the Subject subsetted by the Part is created in the UseCase")
486492
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
487493
@Test
488494
public void createNewUsageSubjectInUseCaseUsage() {
489495
this.createSubjectWithSubsettingInCaseUsage(SysmlPackage.eINSTANCE.getUseCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.USE_CASE_USAGE_ID, USE_CASE);
490496
}
491497

498+
@DisplayName("GIVEN a Case, WHEN creating a new Subject selecting a PartDefinition, THEN the Subject typed by the PartDefinition is created in the Case")
492499
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
493500
@Test
494501
public void createNewDefinitionSubjectInCaseUsage() {
495502
this.createSubjectWithFeatureTypingInCaseUsage(SysmlPackage.eINSTANCE.getCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.CASE_USAGE_ID, CASE);
496503
}
497504

505+
@DisplayName("GIVEN a UseCase, WHEN creating a new Subject selecting a PartDefinition, THEN the Subject typed by the PartDefinition is created in the UseCase")
498506
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
499507
@Test
500508
public void createNewDefinitionSubjectInUseCaseUsage() {
501509
this.createSubjectWithFeatureTypingInCaseUsage(SysmlPackage.eINSTANCE.getUseCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.USE_CASE_USAGE_ID, USE_CASE);
502510
}
503511

512+
@DisplayName("GIVEN a Case, WHEN creating a new Subject without selection, THEN the Subject without specialization is created in the Case")
513+
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
514+
@Test
515+
public void createNewSubjectWithoutSpecializationInCaseUsage() {
516+
this.createSubjectWithoutSpecializationInCaseUsage(SysmlPackage.eINSTANCE.getCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.CASE_USAGE_ID, CASE);
517+
}
518+
519+
@DisplayName("GIVEN a UseCase, WHEN creating a new Subject without selection, THEN the Subject without specialization is created in the UseCase")
520+
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
521+
@Test
522+
public void createNewSubjectWithoutSpecializationInUseCaseUsage() {
523+
this.createSubjectWithoutSpecializationInCaseUsage(SysmlPackage.eINSTANCE.getUseCaseUsage(), GeneralViewWithTopNodesTestProjectData.SemanticIds.USE_CASE_USAGE_ID, USE_CASE);
524+
}
525+
504526
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
505527
@Test
506528
public void createNewActorWithSubsettingInCaseUsage() {
@@ -538,11 +560,8 @@ private void createSubjectWithSubsettingInCaseUsage(EClass caseUsageSubclass, St
538560
EClass childEClass = SysmlPackage.eINSTANCE.getReferenceUsage();
539561
String creationToolName = "New Subject";
540562
EReference containmentReference = SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter();
541-
List<ToolVariable> variables = new ArrayList<>();
542-
String existingPartId = "2c5fe5a5-18fe-40f4-ab66-a2d91ab7df6a";
543-
variables.add(new ToolVariable("selectedObject", existingPartId, ToolVariableType.OBJECT_ID));
544563

545-
Runnable createNodeRunnable = this.creationTestsService.createNode(diagramDescriptionIdProvider, diagram, caseUsageSubclass, targetObjectId, creationToolName, variables);
564+
Runnable createNodeRunnable = this.creationTestsService.createNodeWithSelectionDialogWithSingleSelection(diagramDescriptionIdProvider, diagram, caseUsageSubclass, targetObjectId, creationToolName, GeneralViewWithTopNodesTestProjectData.SemanticIds.PART_USAGE_ID);
546565

547566
Consumer<Object> diagramCheck = assertRefreshedDiagramThat(newDiagram -> {
548567
var initialDiagram = diagram.get();
@@ -566,28 +585,24 @@ private void createSubjectWithSubsettingInCaseUsage(EClass caseUsageSubclass, St
566585
.check(initialDiagram, newDiagram);
567586
});
568587

569-
ISemanticChecker semanticChecker = (editingContext) -> {
570-
Object semanticRootObject = this.objectSearchService.getObject(editingContext, GeneralViewWithTopNodesTestProjectData.SemanticIds.PACKAGE_1_ID).orElse(null);
571-
assertThat(semanticRootObject).isInstanceOf(Element.class);
572-
Element semanticRootElement = (Element) semanticRootObject;
573-
Optional<ReferenceUsage> optParentElement = EMFUtils.allContainedObjectOfType(semanticRootElement, ReferenceUsage.class)
574-
.filter(element -> Objects.equals(element.getName(), "subject"))
575-
.findFirst();
576-
assertThat(optParentElement).isPresent();
577-
var referenceUsage = optParentElement.get();
578-
EList<Subsetting> subjectSubsets = referenceUsage.getOwnedSubsetting();
579-
assertFalse(subjectSubsets.isEmpty());
580-
assertThat(subjectSubsets.get(0).getSubsettedFeature().getName()).isEqualTo("part");
588+
Consumer<Object> additionalCheck = referencedObject -> {
589+
assertThat(referencedObject)
590+
.isInstanceOf(ReferenceUsage.class)
591+
.asInstanceOf(type(ReferenceUsage.class))
592+
.satisfies(referenceUsage -> {
593+
EList<Subsetting> subjectSubsets = referenceUsage.getOwnedSubsetting();
594+
assertThat(subjectSubsets).isNotEmpty();
595+
assertThat(subjectSubsets.get(0).getSubsettedFeature().getName()).isEqualTo("part");
596+
});
581597
};
582-
Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker(parentLabel, containmentReference, childEClass));
583-
Runnable semanticCheck2 = this.semanticCheckerService.checkEditingContext(semanticChecker);
598+
599+
Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker(parentLabel, containmentReference, childEClass, additionalCheck));
584600

585601
StepVerifier.create(flux)
586602
.consumeNextWith(initialDiagramContentConsumer)
587603
.then(createNodeRunnable)
588604
.consumeNextWith(diagramCheck)
589605
.then(semanticCheck)
590-
.then(semanticCheck2)
591606
.thenCancel()
592607
.verify(Duration.ofSeconds(10));
593608
}
@@ -605,11 +620,8 @@ private void createSubjectWithFeatureTypingInCaseUsage(EClass caseUsageSubclass,
605620
EClass childEClass = SysmlPackage.eINSTANCE.getReferenceUsage();
606621
String creationToolName = "New Subject";
607622
EReference containmentReference = SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter();
608-
List<ToolVariable> variables = new ArrayList<>();
609-
String existingPartDefId = GeneralViewWithTopNodesTestProjectData.SemanticIds.PART_DEFINITION_ID;
610-
variables.add(new ToolVariable("selectedObject", existingPartDefId, ToolVariableType.OBJECT_ID));
611623

612-
Runnable createNodeRunnable = this.creationTestsService.createNode(diagramDescriptionIdProvider, diagram, caseUsageSubclass, targetObjectId, creationToolName, variables);
624+
Runnable createNodeRunnable = this.creationTestsService.createNodeWithSelectionDialogWithSingleSelection(diagramDescriptionIdProvider, diagram, caseUsageSubclass, targetObjectId, creationToolName, GeneralViewWithTopNodesTestProjectData.SemanticIds.PART_DEFINITION_ID);
613625

614626
Consumer<Object> diagramCheck = assertRefreshedDiagramThat(newDiagram -> {
615627
var initialDiagram = diagram.get();
@@ -633,28 +645,83 @@ private void createSubjectWithFeatureTypingInCaseUsage(EClass caseUsageSubclass,
633645
.check(initialDiagram, newDiagram);
634646
});
635647

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

652720
StepVerifier.create(flux)
653721
.consumeNextWith(initialDiagramContentConsumer)
654722
.then(createNodeRunnable)
655723
.consumeNextWith(diagramCheck)
656724
.then(semanticCheck)
657-
.then(semanticCheck2)
658725
.thenCancel()
659726
.verify(Duration.ofSeconds(10));
660727
}

0 commit comments

Comments
 (0)