/* * ****************************************************************************** * MontiCore Language Workbench * Copyright (c) 2015, 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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import de.monticore.symboltable.mocks.languages.entity.ActionSymbol; import de.monticore.symboltable.mocks.languages.entity.EntitySymbol; import de.monticore.symboltable.mocks.languages.scandentity.Action2StateAdapter; import de.monticore.symboltable.mocks.languages.scandentity.Action2StateTransitiveResolvingFilter; import de.monticore.symboltable.mocks.languages.scandentity.Entity2ScAdapter; import de.monticore.symboltable.mocks.languages.scandentity.Entity2ScTransitiveResolvingFilter; import de.monticore.symboltable.mocks.languages.scandentity.Entity2StateAdapter; import de.monticore.symboltable.mocks.languages.scandentity.Entity2StateTransitiveResolvingFilter; import de.monticore.symboltable.mocks.languages.scandentity.Sc2ActionAdapter; import de.monticore.symboltable.mocks.languages.scandentity.Sc2ActionTransitiveResolvingFilter; import de.monticore.symboltable.mocks.languages.scandentity.Sc2EntityAdapter; import de.monticore.symboltable.mocks.languages.scandentity.Sc2EntityTransitiveResolvingFilter; import de.monticore.symboltable.mocks.languages.scandentity.State2EntityTransitiveResolvingFilter; import de.monticore.symboltable.mocks.languages.statechart.StateChartSymbol; import de.monticore.symboltable.mocks.languages.statechart.StateSymbol; import de.monticore.symboltable.resolving.CommonResolvingFilter; import org.junit.Test; /** * @author Pedram Mir Seyed Nazari * */ public class AdaptedResolvingTest { @Test public void testAdaptedResolvingInSameScope() { final MutableScope scope = new CommonScope(true); final EntitySymbol entity = new EntitySymbol("Entity"); final StateChartSymbol sc = new StateChartSymbol("Sc"); scope.add(entity); scope.add(sc); scope.addResolver(CommonResolvingFilter.create(EntitySymbol.KIND)); scope.addResolver(CommonResolvingFilter.create(StateChartSymbol.KIND)); assertTrue(scope.resolve("Entity", EntitySymbol.KIND).isPresent()); assertTrue(scope.resolve("Sc", StateChartSymbol.KIND).isPresent()); // adapted resolving assertFalse(scope.resolve("Sc", EntitySymbol.KIND).isPresent()); // Statechart -> Entity scope.addResolver(new Sc2EntityTransitiveResolvingFilter()); final EntitySymbol sc2entity = scope.<EntitySymbol>resolve("Sc", EntitySymbol.KIND).orElse(null); assertNotNull(sc2entity); assertEquals("Sc", sc2entity.getName()); assertTrue(sc2entity instanceof Sc2EntityAdapter); assertSame(sc, ((Sc2EntityAdapter) sc2entity).getAdaptee()); // Entity -> State assertFalse(scope.resolve("Entity", StateSymbol.KIND).isPresent()); scope.addResolver(new Entity2StateTransitiveResolvingFilter()); final StateSymbol entity2state = scope.<StateSymbol>resolve("Entity", StateSymbol.KIND) .orElse(null); assertNotNull(entity2state); assertEquals("Entity", entity2state.getName()); assertTrue(entity2state instanceof Entity2StateAdapter); assertSame(entity, ((Entity2StateAdapter) entity2state).getAdaptee()); } @Test public void testAdaptedResolvingInDifferentScope() { final MutableScope parentScope = new CommonScope(true); final MutableScope subScope = new CommonScope(true); parentScope.addSubScope(subScope); final EntitySymbol entity = new EntitySymbol("Entity"); final StateChartSymbol sc = new StateChartSymbol("Sc"); // Symbols are defined in parent scope... parentScope.add(entity); parentScope.add(sc); // ...Resolving filters are only registered in the sub scope. subScope.addResolver(CommonResolvingFilter.create(EntitySymbol.KIND)); subScope.addResolver(CommonResolvingFilter.create(StateChartSymbol.KIND)); subScope.addResolver(new Sc2EntityTransitiveResolvingFilter()); subScope.addResolver(new Entity2StateTransitiveResolvingFilter()); // Symbols cannot be resolved starting in the parent scope, since no resolving filters are // registered there. assertFalse(parentScope.<EntitySymbol>resolve("Sc", EntitySymbol.KIND).isPresent()); assertFalse(parentScope.<StateSymbol>resolve("Entity", StateSymbol.KIND).isPresent()); // Start resolving in sub scope. // Statechart -> Entity final EntitySymbol sc2entity = subScope.<EntitySymbol>resolve("Sc", EntitySymbol.KIND).orElse(null); assertNotNull(sc2entity); assertEquals("Sc", sc2entity.getName()); assertTrue(sc2entity instanceof Sc2EntityAdapter); assertSame(sc, ((Sc2EntityAdapter) sc2entity).getAdaptee()); // Entity -> State final StateSymbol entity2state = subScope.<StateSymbol>resolve("Entity", StateSymbol.KIND).orElse(null); assertNotNull(entity2state); assertEquals("Entity", entity2state.getName()); assertTrue(entity2state instanceof Entity2StateAdapter); assertSame(entity, ((Entity2StateAdapter) entity2state).getAdaptee()); } @Test public void testTransitiveAdaptedResolvingInSameScope() { final MutableScope scope = new CommonScope(true); final EntitySymbol entity = new EntitySymbol("Entity"); final StateChartSymbol sc = new StateChartSymbol("Sc"); final StateSymbol state = new StateSymbol("state"); scope.add(entity); scope.add(sc); scope.add(state); scope.addResolver(CommonResolvingFilter.create(EntitySymbol.KIND)); scope.addResolver(CommonResolvingFilter.create(StateChartSymbol.KIND)); scope.addResolver(CommonResolvingFilter.create(StateSymbol.KIND)); // Adapted resolving filters scope.addResolver(new Entity2StateTransitiveResolvingFilter()); scope.addResolver(new Sc2EntityTransitiveResolvingFilter()); // Statechart -> Entity -> State => (((Statechart) -> Entity) -> State) final StateSymbol sc2entity2state = scope.<StateSymbol>resolve("Sc", StateSymbol.KIND).orElse(null); assertNotNull(sc2entity2state); assertEquals("Sc", sc2entity2state.getName()); // (((Statechart) -> Entity) -> State) assertTrue(sc2entity2state instanceof Entity2StateAdapter); final Entity2StateAdapter adap1 = (Entity2StateAdapter) sc2entity2state; // ((Statechart) -> Entity) assertTrue(adap1.getAdaptee() instanceof Sc2EntityAdapter); final Sc2EntityAdapter adap2 = (Sc2EntityAdapter) adap1.getAdaptee(); // (Statechart) assertSame(sc, adap2.getAdaptee()); } @Test public void testCircularAdaptedResolvingDependencies() { final MutableScope scope = new CommonScope(true); final EntitySymbol entity = new EntitySymbol("Entity"); final StateChartSymbol sc = new StateChartSymbol("Sc"); scope.add(entity); scope.add(sc); scope.addResolver(CommonResolvingFilter.create(EntitySymbol.KIND)); scope.addResolver(CommonResolvingFilter.create(StateChartSymbol.KIND)); assertTrue(scope.resolve("Entity", EntitySymbol.KIND).isPresent()); assertTrue(scope.resolve("Sc", StateChartSymbol.KIND).isPresent()); // StateChart -> Entity scope.addResolver(new Sc2EntityTransitiveResolvingFilter()); final EntitySymbol sc2entity = scope.<EntitySymbol>resolve("Sc", EntitySymbol.KIND).orElse(null); assertNotNull(sc2entity); assertEquals("Sc", sc2entity.getName()); assertTrue(sc2entity instanceof Sc2EntityAdapter); assertSame(sc, ((Sc2EntityAdapter) sc2entity).getAdaptee()); // Now a Entity -> Statechart adapter is added, hence (theoretically) a circular dependency // exists: Entity -> StateChart -> Entity // The resolving mechanismus should recognize this case and stop after Entity -> StateChart scope.addResolver(new Entity2ScTransitiveResolvingFilter()); final StateChartSymbol entity2sc = scope.<StateChartSymbol>resolve("Entity", StateChartSymbol.KIND).orElse(null); assertNotNull(entity2sc); assertEquals("Entity", entity2sc.getName()); assertTrue(entity2sc instanceof Entity2ScAdapter); assertSame(entity, ((Entity2ScAdapter) entity2sc).getAdaptee()); } @Test public void testTransitiveCircularAdaptedResolvingDependencies() { final MutableScope scope = new CommonScope(true); final EntitySymbol entity = new EntitySymbol("Entity"); // Add all kinds of symbols to ensure that really the correct one is resolved scope.add(entity); scope.add(new ActionSymbol("action")); scope.add(new StateChartSymbol("Sc")); scope.add(new StateSymbol("state")); scope.addResolver(CommonResolvingFilter.create(EntitySymbol.KIND)); scope.addResolver(CommonResolvingFilter.create(ActionSymbol.KIND)); scope.addResolver(CommonResolvingFilter.create(StateChartSymbol.KIND)); scope.addResolver(CommonResolvingFilter.create(StateSymbol.KIND)); // Adapted resolving filters scope.addResolver(new Entity2ScTransitiveResolvingFilter()); scope.addResolver(new Action2StateTransitiveResolvingFilter()); scope.addResolver(new Sc2ActionTransitiveResolvingFilter()); scope.addResolver(new State2EntityTransitiveResolvingFilter()); // Circular dependency: Entity -> StateChart -> Action -> State -> Entity // The resolving mechanism should recognize this case and stop after Entity -> StateChart final StateSymbol entity2state = scope.<StateSymbol>resolve("Entity", StateSymbol.KIND).orElse(null); assertNotNull(entity2state); assertEquals("Entity", entity2state.getName()); // NOTE: the last adapter (i.e., Action -> State) is returned. assertTrue(entity2state instanceof Action2StateAdapter); assertTrue(((Action2StateAdapter) entity2state).getAdaptee() instanceof Sc2ActionAdapter); assertTrue(((Sc2ActionAdapter)((Action2StateAdapter) entity2state).getAdaptee()).getAdaptee() instanceof Entity2ScAdapter); // Finally, the state is just an entity. assertSame(entity, ((Entity2ScAdapter)((Sc2ActionAdapter) ((Action2StateAdapter) entity2state) .getAdaptee()).getAdaptee()).getAdaptee()); } }