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
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.cdgen.cocos;

import de.monticore.cdassociation._ast.ASTCDAssocSide;
import de.monticore.cdassociation._ast.ASTCDAssociation;
import de.monticore.cdbasis._ast.ASTCDDefinition;
import de.monticore.cdbasis._ast.ASTCDType;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
* Checks that generated association references are unique.
*/
public class CDAssociationReferenceUnique extends CDAssociationUniqueInHierarchy {

@Override
public void check(ASTCDDefinition node) {
List<ASTCDAssociation> alreadyChecked = new ArrayList<>();

// we check for each pair of associations
for (ASTCDAssociation assoc2 : node.getCDAssociationsList()) {
for (ASTCDAssociation assoc1 : alreadyChecked) {
for (AssociationReference ref1 : getAssociationReferences(assoc1)) {
for (AssociationReference ref2 : getAssociationReferences(assoc2)) {
if (ref1.name.equals(ref2.name)) {
checkRef(node, ref1.sourceType, ref2.sourceType, assoc2);
}
}
}
}

alreadyChecked.add(assoc2);
}
}

@Override
protected void checkRef(ASTCDDefinition node, ASTCDType type1, ASTCDType type2,
ASTCDAssociation assoc1) {
if (type1 == null || type2 == null) {
return;
}
super.checkRef(node, type1, type2, assoc1);
}

protected List<AssociationReference> getAssociationReferences(ASTCDAssociation assoc) {
List<AssociationReference> references = new ArrayList<>();

boolean navigableLeft = assoc.getCDAssocDir().isDefinitiveNavigableLeft();
boolean navigableRight = assoc.getCDAssocDir().isDefinitiveNavigableRight();
boolean undirected = !navigableLeft && !navigableRight;

if (navigableRight || undirected) {
references.add(new AssociationReference(findTypeByFullName(assoc, assoc.getLeftQualifiedName()
.getQName()), deriveReferenceName(assoc, AssocSide.RIGHT)));
}
if (navigableLeft || undirected) {
references.add(new AssociationReference(findTypeByFullName(assoc, assoc
.getRightQualifiedName().getQName()), deriveReferenceName(assoc, AssocSide.LEFT)));
}

return references;
}

protected String deriveReferenceName(ASTCDAssociation assoc, AssocSide side) {
ASTCDAssocSide assocSide;
if (side.equals(AssocSide.LEFT)) {
assocSide = assoc.getLeft();
}
else {
assocSide = assoc.getRight();
}
if (assoc.isPresentName()) {
return StringUtils.uncapitalize(assoc.getName());
}
else if (assocSide.isPresentCDRole()) {
return assocSide.getCDRole().getName();
}
else {
return StringUtils.uncapitalize(assocSide.getMCQualifiedType().getMCQualifiedName()
.getBaseName());
}
}

protected enum AssocSide {
LEFT, RIGHT;
}

protected static class AssociationReference {

protected final ASTCDType sourceType;

protected final String name;

protected AssociationReference(ASTCDType sourceType, String name) {
this.sourceType = sourceType;
this.name = name;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.cdgen.cocos;

import de.monticore.cd4code._cocos.CD4CodeCoCoChecker;
import de.monticore.cd4code.cocos.AbstractJavaGenCoCoTest;
import java.io.IOException;
import org.junit.jupiter.api.Test;

public class CDAssociationReferenceUniqueTest extends AbstractJavaGenCoCoTest {

@Override
protected CD4CodeCoCoChecker createChecker() {
CD4CodeCoCoChecker checker = new CD4CodeCoCoChecker();
checker.addCoCo(new CDAssociationReferenceUnique());
return checker;
}

private static final String ERROR_CODE = "0xCDCE1";

@Test
public void testUniqueNames() throws IOException {
String model = "classdiagram UniqueAssocs {" + " class A; class B;" + " association A -> B;"
+ " association A (l) -> (r) B;" + "}";
runTest(model, false);
}

@Test
public void testDuplicatesWithExplicitRoles() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association A -> (b) B;" + "}";
runTestForErrorCode(model, ERROR_CODE);
}

@Test
public void testDuplicatesWithImplicitRoles() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association A -> B;" + "}";
runTestForErrorCode(model, ERROR_CODE);
}

@Test
public void testUniqueExplicitRole() throws IOException {
String model = "classdiagram UniqueAssocs {" + " class A; class B;" + " association A -> B;"
+ " association A -> (other) B;" + "}";
runTest(model, false);
}

@Test
public void testDuplicatesInReverse() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association B <- A;" + "}";
runTestForErrorCode(model, ERROR_CODE);
}

@Test
public void testUniqueAssocName() throws IOException {
String model = "classdiagram UniqueAssocs {" + " class A; class B;"
+ " association assoc1 A -> B;" + " association assoc2 A -> B;" + "}";
runTest(model, false);
}

@Test
public void testUniqueAssocNameWithSameRole() throws IOException {
String model = "classdiagram UniqueAssocs {" + " class A; class B;"
+ " association assoc1 A -> (b) B;" + " association assoc2 A -> (b) B;" + "}";
runTest(model, false);
}

}
Loading