/*
* ******************************************************************************
* MontiCore Language Workbench
* Copyright (c) 2016, MontiCore, All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* ******************************************************************************
*/
package de.monticore.symboltable;
import de.monticore.ModelingLanguage;
import de.monticore.io.paths.ModelPath;
import de.monticore.symboltable.mocks.languages.entity.EntityLanguage;
import de.monticore.symboltable.mocks.languages.entity.EntitySymbol;
import de.monticore.symboltable.mocks.languages.entity.EntitySymbolReference;
import de.monticore.symboltable.mocks.languages.entity.PropertySymbol;
import de.monticore.symboltable.modifiers.BasicAccessModifier;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Optional;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* @author Pedram Mir Seyed Nazari
*
*/
public class ResolvingImportedScopesTest {
@Test
public void testOnlyConsiderExplicitlyImportedScopesWhenResolvingInImportedScope() {
final ModelingLanguage language = new EntityLanguage();
final ResolvingConfiguration resolvingConfiguration = new ResolvingConfiguration();
resolvingConfiguration.addTopScopeResolvers(language.getResolvingFilters());
final GlobalScope gs = new GlobalScope(new ModelPath(), language, resolvingConfiguration);
final ArtifactScope as = new ArtifactScope(Optional.empty(), "p", new ArrayList<>());
gs.addSubScope(as);
as.setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
final PropertySymbol asProp = new PropertySymbol("asProp", new EntitySymbolReference("foo", as));
asProp.setAccessModifier(BasicAccessModifier.PROTECTED);
as.add(asProp);
final EntitySymbol supEntity = new EntitySymbol("SupEntity");
as.add(supEntity);
supEntity.getMutableSpannedScope().setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
assertTrue(supEntity.getSpannedScope().resolve("asProp", PropertySymbol.KIND).isPresent());
final PropertySymbol supProp = new PropertySymbol("supProp", new EntitySymbolReference("bar", supEntity.getSpannedScope()));
supProp.setAccessModifier(BasicAccessModifier.PROTECTED);
supEntity.addProperty(supProp);
assertTrue(supEntity.getSpannedScope().resolve("supProp", PropertySymbol.KIND).isPresent());
final EntitySymbol subEntity = new EntitySymbol("SubEntity");
gs.add(subEntity);
subEntity.getMutableSpannedScope().setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
subEntity.setSuperClass(new EntitySymbolReference("p.SupEntity", gs));
assertTrue(subEntity.getSuperClass().get().existsReferencedSymbol());
// Resolving property that is defined in super entity (and not private) should work
assertTrue(subEntity.getSpannedScope().resolve("supProp", PropertySymbol.KIND).isPresent());
// Resolving property that is defined in the enclosing scope of the super entity should not work
assertFalse(subEntity.getSpannedScope().resolve("asProp", PropertySymbol.KIND).isPresent());
}
@Test
public void testSymbolInImportedScopeHasHigherPriorityThanSymbolInEnclosingScope() {
final ModelingLanguage language = new EntityLanguage();
final ResolvingConfiguration resolvingConfiguration = new ResolvingConfiguration();
resolvingConfiguration.addTopScopeResolvers(language.getResolvingFilters());
final GlobalScope gs = new GlobalScope(new ModelPath(), language, resolvingConfiguration);
final ArtifactScope as = new ArtifactScope(Optional.empty(), "", new ArrayList<>());
gs.addSubScope(as);
as.setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
final PropertySymbol asProp = new PropertySymbol("prop", new EntitySymbolReference("foo", as));
asProp.setAccessModifier(BasicAccessModifier.PROTECTED);
as.add(asProp);
final EntitySymbol subEntity = new EntitySymbol("SubEntity");
as.add(subEntity);
subEntity.getMutableSpannedScope().setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
subEntity.setSuperClass(new EntitySymbolReference("SupEntity", subEntity.getEnclosingScope()));
final EntitySymbol supEntity = new EntitySymbol("SupEntity");
gs.add(supEntity);
supEntity.getMutableSpannedScope().setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
final PropertySymbol supProp = new PropertySymbol("prop", new EntitySymbolReference("bar", supEntity.getEnclosingScope()));
supProp.setAccessModifier(BasicAccessModifier.PROTECTED);
supEntity.addProperty(supProp);
// Resolving "prop" in sub enity should resolve to (non-private) property symbol of super entity (instead of enclosing scope)
final PropertySymbol resolvedProp = subEntity.getSpannedScope().<PropertySymbol>resolve("prop", PropertySymbol.KIND).get();
assertSame(supProp, resolvedProp);
}
@Test
public void testResolutionContinuesWIthPackageLocalModifierIfSuperTypeIsInSamePackage() {
final ModelingLanguage language = new EntityLanguage();
final ResolvingConfiguration resolvingConfiguration = new ResolvingConfiguration();
resolvingConfiguration.addTopScopeResolvers(language.getResolvingFilters());
final GlobalScope gs = new GlobalScope(new ModelPath(), language, resolvingConfiguration);
final ArtifactScope asSub = new ArtifactScope(Optional.empty(), "p.q", new ArrayList<>());
gs.addSubScope(asSub);
asSub.setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
final EntitySymbol subEntity = new EntitySymbol("SubEntity");
asSub.add(subEntity);
subEntity.getMutableSpannedScope().setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
subEntity.setSuperClass(new EntitySymbolReference("SupEntity", subEntity.getEnclosingScope()));
final ArtifactScope asSup = new ArtifactScope(Optional.empty(), "p.q", new ArrayList<>());
gs.addSubScope(asSup);
asSup.setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
final EntitySymbol supEntity = new EntitySymbol("SupEntity");
asSup.add(supEntity);
supEntity.getMutableSpannedScope().setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
final PropertySymbol supProp = new PropertySymbol("prop", new EntitySymbolReference("bar", supEntity.getEnclosingScope()));
supProp.setAccessModifier(BasicAccessModifier.PACKAGE_LOCAL);
supEntity.addProperty(supProp);
// SubEntity and SupEntity are in same package, hence, package-local field "prop" can be resolved.
PropertySymbol resolvedProp = subEntity.getSpannedScope().<PropertySymbol>resolve("prop", PropertySymbol.KIND, BasicAccessModifier.PRIVATE).get();
assertSame(supProp, resolvedProp);
}
@Test
public void testResolutionContinuesWithProtectedModifierIfSuperTypeIsInDifferentPackage() {
final ModelingLanguage language = new EntityLanguage();
final ResolvingConfiguration resolvingConfiguration = new ResolvingConfiguration();
resolvingConfiguration.addTopScopeResolvers(language.getResolvingFilters());
final GlobalScope gs = new GlobalScope(new ModelPath(), language, resolvingConfiguration);
final ArtifactScope asSub = new ArtifactScope(Optional.empty(), "p.q", singletonList(new ImportStatement("x.y", true)));
gs.addSubScope(asSub);
asSub.setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
final EntitySymbol subEntity = new EntitySymbol("SubEntity");
asSub.add(subEntity);
subEntity.getMutableSpannedScope().setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
subEntity.setSuperClass(new EntitySymbolReference("SupEntity", subEntity.getEnclosingScope()));
// Super type is in another package
final ArtifactScope asSup = new ArtifactScope(Optional.empty(), "x.y", new ArrayList<>());
gs.addSubScope(asSup);
asSup.setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
final EntitySymbol supEntity = new EntitySymbol("SupEntity");
asSup.add(supEntity);
supEntity.getMutableSpannedScope().setResolvingFilters(resolvingConfiguration.getTopScopeResolvingFilters());
final PropertySymbol supPropPackageLocal = new PropertySymbol("propPL", new EntitySymbolReference("bar", supEntity.getEnclosingScope()));
supPropPackageLocal.setAccessModifier(BasicAccessModifier.PACKAGE_LOCAL);
supEntity.addProperty(supPropPackageLocal);
final PropertySymbol supPropProtected = new PropertySymbol("propProtected", new EntitySymbolReference("bar", supEntity.getEnclosingScope()));
supPropProtected.setAccessModifier(BasicAccessModifier.PROTECTED);
supEntity.addProperty(supPropProtected);
// SubEntity and SupEntity are not in same package, hence, package-local field "propPL" cannot be resolved...
assertFalse(subEntity.getSpannedScope().<PropertySymbol>resolve("propPL", PropertySymbol.KIND, BasicAccessModifier.PRIVATE).isPresent());
// ...but the protected field "propProtected" can be resolved.
assertTrue(subEntity.getSpannedScope().<PropertySymbol>resolve("propProtected", PropertySymbol.KIND, BasicAccessModifier.PRIVATE).isPresent());
}
}