package com.sap.furcas.referenceresolving.tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.ocl.ecore.opposites.DefaultOppositeEndFinder;
import org.eclipse.ocl.ecore.opposites.OppositeEndFinder;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.sap.furcas.metamodel.FURCAS.textblocks.TextBlock;
import com.sap.furcas.metamodel.FURCAS.textblocks.TextblocksPackage;
import com.sap.furcas.test.fixture.ScenarioFixtureData;
import com.sap.ide.cts.parser.errorhandling.SemanticParserException;
/**
* A test case that use a FURCAS mapping specification (".tcs" file) and based on this produce lexer and
* parser, then parse a text resource and register all reference resolving callbacks. Then, the test
* manipulates the model produced by the parser run and observes how OCL-based property assignments get re-assigned.
*
* @author Axel Uhl (D043530)
*
*/
public class TestPropertyInitReEvaluationWithComplexForeach extends AbstractReferenceResolvingTest {
private static final String LANGUAGE = "BibtexWithComplexForeachPropertyInits";
private static final File TCS = new File("fixtures/BibtexWithComplexForeachPropertyInits.tcs");
private static final File[] METAMODELS = { ScenarioFixtureData.BIBTEXT_METAMODEL, ScenarioFixtureData.BIBTEXT1_METAMODEL };
private EObject johnDoe;
private EObject janeDoll;
private List<EObject> articles;
private EClass authorClass;
private EClass articleClass;
@BeforeClass
public static void setupParser() throws Exception {
setupParser(LANGUAGE, TCS, METAMODELS);
}
/**
* Tests whether an simple addition to a textblock is correctly mapped to an insertion in the model without
* re-creating the parent element.
*
* @throws Exception
*/
@Before
public void setupInitialModel() throws SemanticParserException {
String textToParse = "article{ Shrt, \"John Doe\"}" +
"article{ Medium, \"John Doe\"}" +
"article{ LongLongLong, \"Jane Doll\"}" +
"author = \"John Doe\"." +
"author = \"Jane Doll\".";
setupModelFromTextToParse(textToParse);
johnDoe = null;
articles = new ArrayList<EObject>(3);
authorClass = null;
articleClass = null;
assertNotNull(rootElement);
EClass bibTexFileClass = rootElement.eClass();
assertEquals("BibTextFile", bibTexFileClass.getName());
for (EObject entry : getECollection(rootElement, "entries")) {
if (entry.eClass().getName().equals("Author")) {
authorClass = entry.eClass();
if (getFeature(entry, "name").equals("John Doe")) {
johnDoe = entry;
} else if (getFeature(entry, "name").equals("Jane Doll")) {
janeDoll = entry;
}
} else if (entry.eClass().getName().equals("Article")) {
articleClass = entry.eClass();
articles.add(entry);
}
}
}
@SuppressWarnings("unchecked")
private List<EObject> getECollection(EObject obj, String feature) {
return (List<EObject>) getFeature(obj, feature);
}
private EObject getEFeature(EObject obj, String feature) {
return (EObject) getFeature(obj, feature);
}
private Object getFeature(EObject obj, String feature) {
return obj.eGet(obj.eClass().getEStructuralFeature(feature));
}
@Test
public void testInitialModel() {
assertNotNull(rootElement);
EList<?> entries = (EList<?>) (rootElement).eGet((rootElement).eClass().getEStructuralFeature("entries"));
assertEquals(5, entries.size());
assertEquals(3, articles.size());
assertNotNull(johnDoe);
assertFalse(getECollection(johnDoe, "revenues").isEmpty());
assertEquals(getECollection(johnDoe, "articles").size(), getECollection(johnDoe, "revenues").size());
assertNotNull(janeDoll);
assertFalse(getECollection(janeDoll, "revenues").isEmpty());
assertEquals(getECollection(janeDoll, "articles").size(), getECollection(janeDoll, "revenues").size());
// now check the reference was set using the right property name
for (EObject article : articles) {
assertNotNull(getEFeature(article, "author"));
}
for (EObject author : new EObject[] { johnDoe, janeDoll }) {
for (EObject revenue : getECollection(author, "revenues")) {
EObject articleOfRevenue = getEFeature(revenue, "article");
String articleName = (String) getFeature(articleOfRevenue, "key");
assertEquals((articleName.length()<5 ? 1 : articleName.length()<10?2:3)*articleName.length(),
getFeature(revenue, "revenueInEUR"));
}
}
}
@Test
public void testChangeArticleNameWithinSameWhenClause() {
testInitialModel(); // just to make sure that for this particular test case evaluation the model is correct, too
for (EObject article : articles) {
if (article.eGet(articleClass.getEStructuralFeature("key")).equals("Shrt")) {
String newArticleName = "Sht";
article.eSet(articleClass.getEStructuralFeature("key"), newArticleName);
// testInitialModel(); // test if everything is still alright after the change
EObject author = (EObject) article.eGet(articleClass.getEStructuralFeature("author"));
@SuppressWarnings("unchecked")
Collection<EObject> revenues = (Collection<EObject>) author.eGet(authorClass.getEStructuralFeature("revenues"));
boolean found = false;
for (EObject revenue : revenues) {
EObject articleOfRevenue = (EObject) revenue.eGet(revenue.eClass().getEStructuralFeature("article"));
if (articleOfRevenue == article) {
// We clearly had the case that the testInitialModel() call above succeeded but the following
// assertion failed. This makes it likely that the article.eSet call above cause a model change
// which can only have resulted from an event handler that reacted to the change
assertEquals(newArticleName.length(), revenue.eGet(revenue.eClass().getEStructuralFeature("revenueInEUR")));
found = true;
}
}
assertTrue(found);
}
}
}
@Test
public void testChangeArticleNameCausingWhenClauseSelectionToChange() {
testInitialModel(); // just to make sure that for this particular test case evaluation the model is correct, too
for (EObject article : articles) {
if (article.eGet(articleClass.getEStructuralFeature("key")).equals("Shrt")) {
String newArticleName = "Short";
article.eSet(articleClass.getEStructuralFeature("key"), newArticleName); // takes it to >= 5, expecting revenue to double
// testInitialModel(); // test if everything is still alright after the change
EObject author = (EObject) article.eGet(articleClass.getEStructuralFeature("author"));
@SuppressWarnings("unchecked")
Collection<EObject> revenues = (Collection<EObject>) author.eGet(authorClass.getEStructuralFeature("revenues"));
boolean found = false;
for (EObject revenue : revenues) {
EObject articleOfRevenue = (EObject) revenue.eGet(revenue.eClass().getEStructuralFeature("article"));
if (articleOfRevenue == article) {
// We clearly had the case that the testInitialModel() call above succeeded but the following
// assertion failed. This makes it likely that the article.eSet call above cause a model change
// which can only have resulted from an event handler that reacted to the change
assertEquals(2*newArticleName.length(), revenue.eGet(revenue.eClass().getEStructuralFeature("revenueInEUR")));
found = true;
}
}
assertTrue(found);
}
}
}
/**
* Tests that updating an author's name does not trigger the property init through the
* impact analysis in case the author hasn't been created using concrete syntax and
* therefore no text block exists for the property init's execution.
*/
@Test
public void testChangeAuthorNameForAuthorNotCreatedByConcreteSyntax() {
EObject newAuthor = authorClass.getEPackage().getEFactoryInstance().create(authorClass);
johnDoe.eResource().getContents().add(newAuthor);
EObject newAuthorsArticle = articleClass.getEPackage().getEFactoryInstance().create(articleClass);
@SuppressWarnings("unchecked")
EList<EObject> articleList = (EList<EObject>) newAuthor.eGet(authorClass.getEStructuralFeature("articles"));
articleList.add(newAuthorsArticle);
newAuthor.eSet(authorClass.getEStructuralFeature("name"), "The New Author");
assertNull(newAuthorsArticle.eGet(articleClass.getEStructuralFeature("location")));
}
@Test
public void testAddArticleAndExpectRevenueLedgerCreation() throws Exception {
EObject newArticle = articleClass.getEPackage().getEFactoryInstance().create(articleClass);
newArticle.eSet(articleClass.getEStructuralFeature("key"), "New Article's Name");
newArticle.eSet(articleClass.getEStructuralFeature("location"), "Location of the New Article");
@SuppressWarnings("unchecked")
EList<EObject> johnsArticles = (EList<EObject>) johnDoe.eGet(authorClass.getEStructuralFeature("articles"));
johnsArticles.add(newArticle);
@SuppressWarnings("unchecked")
EList<EObject> revenues = (EList<EObject>) johnDoe.eGet(authorClass.getEStructuralFeature("revenues"));
assertEquals(johnsArticles.size(), revenues.size());
// now ensure that a ForEachContext has been created for the RevenueLedger construction
OppositeEndFinder oppositeEndFinder = DefaultOppositeEndFinder.getInstance();
Set<EObject> johnsArticlesAsSet = new HashSet<EObject>(johnsArticles);
Set<EObject> revenueLedgerArticles = new HashSet<EObject>();
for (EObject revenueLedger : revenues) {
EObject articleOfRevenue = (EObject) revenueLedger.eGet(revenueLedger.eClass().getEStructuralFeature("article"));
String articleName = (String) articleOfRevenue.eGet(articleClass.getEStructuralFeature("key"));
assertEquals((articleName.length()<5 ? 1 : articleName.length()<10?2:3)*articleName.length(),
revenueLedger.eGet(revenueLedger.eClass().getEStructuralFeature("revenueInEUR")));
revenueLedgerArticles.add(articleOfRevenue);
assertEquals(
"Expected to find exactly one ForEachContext for produced RevenueLedger element " + revenueLedger,
1,
oppositeEndFinder.navigateOppositePropertyWithBackwardScope(
TextblocksPackage.eINSTANCE.getForEachExecution_ResultModelElement(), revenueLedger).size());
EObject author = revenueLedger.eContainer();
TextBlock authorCreationRecord = (TextBlock) oppositeEndFinder
.navigateOppositePropertyWithBackwardScope(
TextblocksPackage.eINSTANCE.getTextBlock_CorrespondingModelElements(), author)
.iterator().next();
assertEquals("Expected exactly as many ForEachContext records as we have RevenueLedger objects for author "
+ author, revenues.size(), authorCreationRecord.getForEachExecutions().size());
}
assertEquals(johnsArticlesAsSet, revenueLedgerArticles);
}
}