diff --git a/bundles/com.e1c.v8codestyle.autosort/src/com/e1c/v8codestyle/internal/autosort/SortService.java b/bundles/com.e1c.v8codestyle.autosort/src/com/e1c/v8codestyle/internal/autosort/SortService.java index b72886ac..70e5a53c 100644 --- a/bundles/com.e1c.v8codestyle.autosort/src/com/e1c/v8codestyle/internal/autosort/SortService.java +++ b/bundles/com.e1c.v8codestyle.autosort/src/com/e1c/v8codestyle/internal/autosort/SortService.java @@ -320,11 +320,12 @@ public class SortService { for (Notification notification : notifications) { - if (notification.getEventType() == Notification.ADD) + if (notification.getEventType() == Notification.ADD || notification.getEventType() == Notification.MOVE + || notification.getEventType() == Notification.REMOVE) { Object notifier = notification.getNotifier(); Object value = notification.getNewValue(); - if (notifier instanceof IBmObject && value instanceof MdObject) + if (notifier instanceof IBmObject && (value instanceof MdObject || value == null)) { changedItems.computeIfAbsent(((IBmObject)notifier).bmGetFqn(), k -> new HashSet<>()) .add(listRef); diff --git a/tests/com.e1c.v8codestyle.autosort.itests/src/com/e1c/v8codestyle/autosort/itests/ExternalDependenciesModule.java b/tests/com.e1c.v8codestyle.autosort.itests/src/com/e1c/v8codestyle/autosort/itests/ExternalDependenciesModule.java index 138979d7..77a30ec0 100644 --- a/tests/com.e1c.v8codestyle.autosort.itests/src/com/e1c/v8codestyle/autosort/itests/ExternalDependenciesModule.java +++ b/tests/com.e1c.v8codestyle.autosort.itests/src/com/e1c/v8codestyle/autosort/itests/ExternalDependenciesModule.java @@ -16,6 +16,7 @@ import com._1c.g5.v8.activitytracking.core.ISystemIdleService; import com._1c.g5.v8.dt.core.platform.IBmModelManager; import com._1c.g5.v8.dt.core.platform.IDerivedDataManagerProvider; import com._1c.g5.v8.dt.core.platform.IDtProjectManager; +import com._1c.g5.v8.dt.core.platform.IV8ProjectManager; import com._1c.g5.wiring.AbstractServiceAwareModule; import com.e1c.v8codestyle.autosort.ISortService; import com.e1c.v8codestyle.internal.autosort.AutoSortPlugin; @@ -41,6 +42,7 @@ public class ExternalDependenciesModule bind(ISortService.class).toService(); bind(IBmModelManager.class).toService(); bind(IDtProjectManager.class).toService(); + bind(IV8ProjectManager.class).toService(); bind(ISystemIdleService.class).toService(); bind(IDerivedDataManagerProvider.class).toService(); } diff --git a/tests/com.e1c.v8codestyle.autosort.itests/src/com/e1c/v8codestyle/autosort/itests/SortServiceTest.java b/tests/com.e1c.v8codestyle.autosort.itests/src/com/e1c/v8codestyle/autosort/itests/SortServiceTest.java index 5514d93c..1aa460d5 100644 --- a/tests/com.e1c.v8codestyle.autosort.itests/src/com/e1c/v8codestyle/autosort/itests/SortServiceTest.java +++ b/tests/com.e1c.v8codestyle.autosort.itests/src/com/e1c/v8codestyle/autosort/itests/SortServiceTest.java @@ -18,29 +18,49 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import com._1c.g5.v8.bm.core.IBmObject; import com._1c.g5.v8.bm.core.IBmTransaction; +import com._1c.g5.v8.bm.core.event.BmChangeEvent; +import com._1c.g5.v8.bm.core.event.BmEvent; import com._1c.g5.v8.bm.integration.AbstractBmTask; import com._1c.g5.v8.bm.integration.IBmModel; +import com._1c.g5.v8.bm.integration.event.IBmSyncEventListener; import com._1c.g5.v8.dt.core.platform.IBmModelManager; +import com._1c.g5.v8.dt.core.platform.IConfigurationAware; import com._1c.g5.v8.dt.core.platform.IDtProject; import com._1c.g5.v8.dt.core.platform.IDtProjectManager; +import com._1c.g5.v8.dt.core.platform.IV8Project; +import com._1c.g5.v8.dt.core.platform.IV8ProjectManager; import com._1c.g5.v8.dt.md.sort.MdSortPreferences; +import com._1c.g5.v8.dt.metadata.mdclass.CommonModule; import com._1c.g5.v8.dt.metadata.mdclass.Configuration; +import com._1c.g5.v8.dt.metadata.mdclass.MdClassFactory; import com._1c.g5.v8.dt.testing.GuiceModules; import com._1c.g5.v8.dt.testing.JUnitGuiceRunner; import com._1c.g5.v8.dt.testing.TestingWorkspace; import com.e1c.v8codestyle.autosort.AutoSortPreferences; import com.e1c.v8codestyle.autosort.ISortService; +import com.google.common.base.Preconditions; import com.google.inject.Inject; /** @@ -50,7 +70,6 @@ import com.google.inject.Inject; @GuiceModules(modules = { ExternalDependenciesModule.class }) public class SortServiceTest { - private static final String PROJECT_NAME = "Sort"; @Rule @@ -62,6 +81,9 @@ public class SortServiceTest @Inject public IDtProjectManager dtProjectManager; + @Inject + private IV8ProjectManager v8ProjectManager; + @Inject public IBmModelManager bmModelManager; @@ -153,12 +175,241 @@ public class SortServiceTest assertEquals("ОбщийМодуль", configuration.getCommonModules().get(5).getName()); } + @Ignore("#1365") + @Test + public void testSortAfterRemoveEvent() throws Exception + { + IProject project = testingWorkspace.setUpProject(PROJECT_NAME, getClass()); + assertNotNull(project); + IDtProject dtProject = dtProjectManager.getDtProject(project); + assertNotNull(dtProject); + IV8Project v8Project = v8ProjectManager.getProject(dtProject); + assertNotNull(dtProject); + + IEclipsePreferences autoSortPrefs = AutoSortPreferences.getPreferences(project); + autoSortPrefs.putBoolean(AutoSortPreferences.KEY_ALL_TOP, true); + autoSortPrefs.flush(); + + IEclipsePreferences mdSortPrefs = MdSortPreferences.getPreferences(project); + mdSortPrefs.putBoolean(MdSortPreferences.NATURAL_SORT_ORDER, false); + mdSortPrefs.flush(); + + CountDownLatch waitSortStartedlatch = new CountDownLatch(1); + bmModelManager.addSyncEventListener(bmModelManager.getBmNamespace(project), + new BmEventListener(project, waitSortStartedlatch) + { + boolean isBmObjectRemoved = false; + boolean isStortStarted = false; + + @Override + protected void registerEvent(Notification notification) + { + if (notification.getEventType() == Notification.REMOVE) + { + isBmObjectRemoved = true; + } + else if (notification.getEventType() == Notification.MOVE) + { + isStortStarted = true; + } + } + + @Override + protected boolean isShouldCountDownLatch() + { + return isBmObjectRemoved && isStortStarted; + } + }); + + bmModelManager.getModel(project).execute(new AbstractBmTask("Detach a top object") //$NON-NLS-1$ + { + @Override + public Void execute(IBmTransaction transaction, IProgressMonitor monitor) + { + IBmObject commonModule = transaction.getTopObjectByFqn("CommonModule.ГМодуль"); + Configuration configuration = + transaction.toTransactionObject(((IConfigurationAware)v8Project).getConfiguration()); + configuration.getCommonModules().remove((CommonModule)commonModule); + transaction.detachTopObject(commonModule); + return null; + } + }); + + waitSortStartedlatch.await(); + // wait until sorting is completed. + TimeUnit.SECONDS.sleep(5); + + IBmObject object = getTopObjectByFqn(CONFIGURATION.getName(), dtProject); + assertTrue(object instanceof Configuration); + + Configuration configuration = (Configuration)object; + assertFalse(configuration.getCommonModules().isEmpty()); + + assertEquals("АМ_Модуль", configuration.getCommonModules().get(0).getName()); + assertEquals("АМ2_4Модуль", configuration.getCommonModules().get(1).getName()); + assertEquals("АМодуль", configuration.getCommonModules().get(2).getName()); + assertEquals("БМодуль", configuration.getCommonModules().get(3).getName()); + assertEquals("ОбщийМодуль", configuration.getCommonModules().get(4).getName()); + } + + @Ignore("#1365") + @Test + public void testSortAfterMoveEvent() throws Exception + { + IProject project = testingWorkspace.setUpProject(PROJECT_NAME, getClass()); + assertNotNull(project); + IDtProject dtProject = dtProjectManager.getDtProject(project); + assertNotNull(dtProject); + IV8Project v8Project = v8ProjectManager.getProject(dtProject); + assertNotNull(dtProject); + + IEclipsePreferences autoSortPrefs = AutoSortPreferences.getPreferences(project); + autoSortPrefs.putBoolean(AutoSortPreferences.KEY_ALL_TOP, true); + autoSortPrefs.flush(); + + IEclipsePreferences mdSortPrefs = MdSortPreferences.getPreferences(project); + mdSortPrefs.putBoolean(MdSortPreferences.NATURAL_SORT_ORDER, false); + mdSortPrefs.flush(); + + CountDownLatch waitSortStartedlatch = new CountDownLatch(1); + bmModelManager.addSyncEventListener(bmModelManager.getBmNamespace(project), + new BmEventListener(project, waitSortStartedlatch) + { + private int moveCount = 0; + + @Override + protected void registerEvent(Notification notification) + { + if (notification.getEventType() == Notification.MOVE) + { + moveCount++; + } + } + + @Override + protected boolean isShouldCountDownLatch() + { + return moveCount == 2; + } + }); + + bmModelManager.getModel(project).execute(new AbstractBmTask("Move a top object") //$NON-NLS-1$ + { + @Override + public Void execute(IBmTransaction transaction, IProgressMonitor progressMonitor) + { + IBmObject commonModule = transaction.getTopObjectByFqn("CommonModule.БМодуль"); + Configuration configuration = + transaction.toTransactionObject(((IConfigurationAware)v8Project).getConfiguration()); + configuration.getCommonModules().move(4, (CommonModule)commonModule); + return null; + } + }); + + waitSortStartedlatch.await(); + // wait until sorting is performed. + TimeUnit.SECONDS.sleep(5); + + IBmObject object = getTopObjectByFqn(CONFIGURATION.getName(), dtProject); + assertTrue(object instanceof Configuration); + + Configuration configuration = (Configuration)object; + assertFalse(configuration.getCommonModules().isEmpty()); + + assertEquals("АМ_Модуль", configuration.getCommonModules().get(0).getName()); + assertEquals("АМ2_4Модуль", configuration.getCommonModules().get(1).getName()); + assertEquals("АМодуль", configuration.getCommonModules().get(2).getName()); + assertEquals("БМодуль", configuration.getCommonModules().get(3).getName()); + assertEquals("ГМодуль", configuration.getCommonModules().get(4).getName()); + assertEquals("ОбщийМодуль", configuration.getCommonModules().get(5).getName()); + } + + @Ignore("#1365") + @Test + public void testSortAfterAddEvent() throws Exception + { + IProject project = testingWorkspace.setUpProject(PROJECT_NAME, getClass()); + assertNotNull(project); + IDtProject dtProject = dtProjectManager.getDtProject(project); + assertNotNull(dtProject); + IV8Project v8Project = v8ProjectManager.getProject(dtProject); + assertNotNull(dtProject); + + IEclipsePreferences autoSortPrefs = AutoSortPreferences.getPreferences(project); + autoSortPrefs.putBoolean(AutoSortPreferences.KEY_ALL_TOP, true); + autoSortPrefs.flush(); + + IEclipsePreferences mdSortPrefs = MdSortPreferences.getPreferences(project); + mdSortPrefs.putBoolean(MdSortPreferences.NATURAL_SORT_ORDER, false); + mdSortPrefs.flush(); + + CountDownLatch waitSortStartedlatch = new CountDownLatch(1); + bmModelManager.addSyncEventListener(bmModelManager.getBmNamespace(project), + new BmEventListener(project, waitSortStartedlatch) + { + boolean isBmObjectAdded = false; + boolean isStortStarted = false; + + @Override + protected void registerEvent(Notification notification) + { + if (notification.getEventType() == Notification.ADD) + { + isBmObjectAdded = true; + } + else if (notification.getEventType() == Notification.MOVE) + { + isStortStarted = true; + } + } + + @Override + protected boolean isShouldCountDownLatch() + { + return isBmObjectAdded && isStortStarted; + } + }); + + bmModelManager.getModel(project).execute(new AbstractBmTask("Add a top object") //$NON-NLS-1$ + { + @Override + public Void execute(IBmTransaction transaction, IProgressMonitor progressMonitor) + { + CommonModule commonModule = MdClassFactory.eINSTANCE.createCommonModule(); + commonModule.setName("КМодуль"); + commonModule.setUuid(UUID.randomUUID()); + transaction.attachTopObject((IBmObject)commonModule, "CommonModule.КМодуль"); + + Configuration configuration = + transaction.toTransactionObject(((IConfigurationAware)v8Project).getConfiguration()); + + configuration.getCommonModules().add(commonModule); + return null; + } + }); + + waitSortStartedlatch.await(); + // wait until sorting is performed. + TimeUnit.SECONDS.sleep(5); + + IBmObject object = getTopObjectByFqn(CONFIGURATION.getName(), dtProject); + Configuration configuration = (Configuration)object; + assertFalse(configuration.getCommonModules().isEmpty()); + + assertEquals("АМ_Модуль", configuration.getCommonModules().get(0).getName()); + assertEquals("АМ2_4Модуль", configuration.getCommonModules().get(1).getName()); + assertEquals("АМодуль", configuration.getCommonModules().get(2).getName()); + assertEquals("БМодуль", configuration.getCommonModules().get(3).getName()); + assertEquals("ГМодуль", configuration.getCommonModules().get(4).getName()); + assertEquals("КМодуль", configuration.getCommonModules().get(5).getName()); + assertEquals("ОбщийМодуль", configuration.getCommonModules().get(6).getName()); + } + protected IBmObject getTopObjectByFqn(final String fqn, IDtProject dtProject) { IBmModel model = this.bmModelManager.getModel(dtProject); return model.executeReadonlyTask(new AbstractBmTask("GetObject") { - @Override public IBmObject execute(IBmTransaction transaction, IProgressMonitor progressMonitor) { @@ -166,4 +417,65 @@ public class SortServiceTest } }); } + + private abstract class BmEventListener + implements IBmSyncEventListener + { + private final CountDownLatch latch; + private final IProject project; + + /** + * Creates instance of listener. + * + * @param project project to listen events to, cannot be {@code null} + * @param latch latch waiting until notified about {@code eventType} and starting sort, cannot be {@code null} + */ + public BmEventListener(IProject project, CountDownLatch latch) + { + this.project = Preconditions.checkNotNull(project); + this.latch = Preconditions.checkNotNull(latch); + } + + @Override + public void handleSyncEvent(BmEvent event) + { + for (BmChangeEvent changeEvent : event.getChangeEvents().values()) + { + if (changeEvent.getObject() instanceof IBmObject && ((IBmObject)changeEvent.getObject()).bmIsTop() + && ((IBmObject)changeEvent.getObject()).bmGetFqn() != null) + { + Map> notifications = changeEvent.getNotifications(); + for (Entry> entry : notifications.entrySet()) + { + if (entry.getKey() instanceof EReference + && AutoSortPreferences.isAllowedToSort(project, (EReference)entry.getKey())) + { + for (Notification notification : entry.getValue()) + { + registerEvent(notification); + } + } + } + } + } + if (isShouldCountDownLatch()) + { + latch.countDown(); + } + } + + /** + * Specifies how event must be registered. + * + * @param notification the notification containing event data, cannot be {@code null} + */ + protected abstract void registerEvent(Notification notification); + + /** + * Checks if listener should count down latch. + * + * @return {@code true} if should count down latch, {@code false} otherwise + */ + protected abstract boolean isShouldCountDownLatch(); + } }