package jetbrains.mps.refactoring.test.test;

/*Generated by MPS */

import org.junit.jupiter.api.extension.ExtendWith;
import jetbrains.mps.baseLanguage.unitTest.runtime.EnvironmentAwareExtension;
import jetbrains.mps.logging.Logger;
import org.junit.jupiter.api.Test;
import java.util.List;
import jetbrains.mps.refactoring.participant.RefactoringParticipant;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import jetbrains.mps.lang.core.pluginSolution.plugin.UpdateModelImports;
import jetbrains.mps.lang.core.pluginSolution.plugin.UpdateReferencesParticipantBase;
import jetbrains.mps.lang.structure.pluginSolution.plugin.MoveAspectsParticipant;
import jetbrains.mps.lang.structure.pluginSolution.plugin.LanguageStructureMigrationParticipant;
import jetbrains.mps.lang.migration.pluginSolution.plugin.MoveNodeRefactoringLogParticipant;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.refactoring.participant.plugin.MoveNodesUtil;
import jetbrains.mps.ide.platform.refactoring.NodeLocation;
import org.jetbrains.mps.openapi.language.SProperty;
import org.junit.Assert;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import org.jetbrains.mps.openapi.module.SModule;
import jetbrains.mps.model.ModelDeleteHelper;
import com.intellij.openapi.application.ApplicationManager;
import jetbrains.mps.ide.MPSCoreComponents;
import jetbrains.mps.smodel.language.LanguageRuntime;
import jetbrains.mps.smodel.Language;
import jetbrains.mps.smodel.language.LanguageRegistry;
import jetbrains.mps.smodel.language.ConceptRegistry;
import java.util.ArrayList;
import jetbrains.mps.lang.structure.pluginSolution.plugin.WriteSubconceptMigrationParticipant;
import jetbrains.mps.smodel.runtime.ConceptDescriptor;
import jetbrains.mps.smodel.adapter.MetaAdapterByDeclaration;
import jetbrains.mps.smodel.runtime.illegal.IllegalConceptDescriptor;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import java.util.HashMap;
import java.util.Map;
import jetbrains.mps.smodel.runtime.impl.CompiledConceptDescriptor;
import java.util.Objects;
import jetbrains.mps.nodefs.MPSNodeVirtualFile;
import jetbrains.mps.nodefs.NodeVirtualFileSystem;
import jetbrains.mps.ide.editor.MPSFileNodeEditor;
import jetbrains.mps.project.MPSProject;
import jetbrains.mps.openapi.editor.Editor;
import jetbrains.mps.nodeEditor.NodeEditorComponent;
import java.awt.event.KeyEvent;
import java.util.Collection;
import jetbrains.mps.errors.item.ReportItem;
import jetbrains.mps.project.validation.ValidationUtil;
import jetbrains.mps.project.validation.StructureChecker;
import org.jetbrains.mps.openapi.util.Processor;
import jetbrains.mps.util.Reference;
import jetbrains.mps.ide.ThreadUtils;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPointerOperations;
import jetbrains.mps.smodel.SNodePointer;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.persistence.PersistenceFacade;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModuleOperations;
import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes;
import jetbrains.mps.baseLanguage.closures.runtime.Wrappers;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModelOperations;
import jetbrains.mps.internal.collections.runtime.CollectionSequence;
import jetbrains.mps.ide.migration.AntTaskExecutionUtil;
import com.intellij.openapi.application.ModalityState;
import org.jetbrains.mps.openapi.language.SContainmentLink;

@ExtendWith(EnvironmentAwareExtension.class)
public class MoveConceptRefactoring_Test extends AbstractRefactoringTest {
  private static final Logger LOG = Logger.getLogger(MoveConceptRefactoring_Test.class);
  private static final String PROJECT_PATH = "testbench/modules/testRefactoringWithMigration/MoveConcept_MPS_27372/";
  @Test
  public void test_moveConcept_MPS_27372() throws Exception {
    commonTest((List<RefactoringParticipant.Option> options) -> {
      ListSequence.fromList(options).addElement(UpdateModelImports.OPTION);
      ListSequence.fromList(options).addElement(UpdateReferencesParticipantBase.UpdateReferencesParticipant.OPTION);

      ListSequence.fromList(options).addElement(MoveAspectsParticipant.OPTION);

      ListSequence.fromList(options).addElement(LanguageStructureMigrationParticipant.OPTION);
      ListSequence.fromList(options).addElement(MoveNodeRefactoringLogParticipant.OPTION);
    }, () -> {
      SNodeOperations.deleteNode(getInstanceB());
      SNodeOperations.deleteNode(getConcept_B());
    }, (List<SNode> nodesToMove) -> {
      ListSequence.fromList(nodesToMove).addElement(getConcept_A());

    }, () -> {
      return new MoveNodesUtil.NodeCreatingProcessor(new NodeLocation.NodeLocationRoot(getTargetModel()), project);

    }, () -> project.getRepository().getModelAccess().runReadAction(() -> {
      Iterable<SProperty> properties1 = getInstanceA().getProperties();
      Assert.assertFalse(Sequence.fromIterable(properties1).any((it) -> it.getOwner().getLanguage() == MetaAdapterFactory.getLanguage(0x3e00419d48014badL, 0xbf2a50479218fb53L, "testmaterial.moveConcept.SourceLanguage")));
      Assert.assertTrue(Sequence.fromIterable(properties1).any((it) -> it.getOwner().getLanguage() == MetaAdapterFactory.getLanguage(0x2f6eb168481148adL, 0xbecb56fd47d21d59L, "testmaterial.moveConcept.TargetLanguage")));
    }));
  }
  @Test
  public void test_moveConcept_MPS_27701() throws Exception {
    commonTest((List<RefactoringParticipant.Option> options) -> {
      ListSequence.fromList(options).addElement(UpdateModelImports.OPTION);
      ListSequence.fromList(options).addElement(UpdateReferencesParticipantBase.UpdateReferencesParticipant.OPTION);

      ListSequence.fromList(options).addElement(MoveAspectsParticipant.OPTION);

      ListSequence.fromList(options).addElement(LanguageStructureMigrationParticipant.OPTION);
      ListSequence.fromList(options).addElement(MoveNodeRefactoringLogParticipant.OPTION);
    }, () -> {
      // do nothing
      // do nothing
    }, (List<SNode> nodesToMove) -> {
      ListSequence.fromList(nodesToMove).addElement(getConcept_A());

    }, () -> {
      return new MoveNodesUtil.NodeCreatingProcessor(new NodeLocation.NodeLocationRoot(getTargetModel()), project);

    }, () -> project.getRepository().getModelAccess().runReadAction(() -> {
      Iterable<SProperty> properties1 = getInstanceA().getProperties();
      Iterable<SProperty> properties2 = getInstanceB().getProperties();
      Assert.assertTrue(Sequence.fromIterable(properties2).all((it) -> getInstanceB().getConcept().getProperties().contains(it)));
      Assert.assertFalse(Sequence.fromIterable(properties1).any((it) -> it.getOwner().getLanguage() == MetaAdapterFactory.getLanguage(0x3e00419d48014badL, 0xbf2a50479218fb53L, "testmaterial.moveConcept.SourceLanguage")));
      Assert.assertTrue(Sequence.fromIterable(properties1).any((it) -> it.getOwner().getLanguage() == MetaAdapterFactory.getLanguage(0x2f6eb168481148adL, 0xbecb56fd47d21d59L, "testmaterial.moveConcept.TargetLanguage")));
    }));
  }
  @Test
  public void test_moveConceptWithNotDeployedConcepts() throws Exception {
    // here we test that option 'Update local partitipants' is not shown if language is not deployed
    // cleaning class files to make test behavior determinate:
    // local execution might have .class files copied from project
    // on the buildserver there are no .class files
    runCommand(() -> {
      List<SModule> projectModules = project.getProjectModulesWithGenerators();
      ListSequence.fromList(projectModules).translate((it) -> it.getModels()).visitAll((it) -> new ModelDeleteHelper(it).removeGeneratedArtifacts());
      ApplicationManager.getApplication().getComponent(MPSCoreComponents.class).getClassLoaderManager().reloadModules(projectModules);
      Iterable<LanguageRuntime> projectLanguages = ListSequence.fromList(projectModules).ofType(Language.class).select((it) -> LanguageRegistry.getInstance(project.getRepository()).getLanguage(it));
      // this is a hack needed to clear global registry to unload languages like no languages were loaded at all
      ConceptRegistry.getInstance().afterLanguagesLoaded(projectLanguages);
    });
    final List<RefactoringParticipant.Option> expectedOptions = ListSequence.fromList(new ArrayList<RefactoringParticipant.Option>());
    ListSequence.fromList(expectedOptions).addElement(UpdateModelImports.OPTION);
    ListSequence.fromList(expectedOptions).addElement(UpdateReferencesParticipantBase.UpdateReferencesParticipant.OPTION);

    ListSequence.fromList(expectedOptions).addElement(WriteSubconceptMigrationParticipant.OPTION);
    ListSequence.fromList(expectedOptions).addElement(MoveAspectsParticipant.OPTION);

    ListSequence.fromList(expectedOptions).addElement(LanguageStructureMigrationParticipant.OPTION);
    ListSequence.fromList(expectedOptions).addElement(MoveNodeRefactoringLogParticipant.OPTION);

    runCommand(() -> {
      ConceptDescriptor conceptDescriptor = ConceptRegistry.getInstance().getConceptDescriptor(MetaAdapterByDeclaration.getConcept(getConcept_PropertyContainer()));
      assert conceptDescriptor instanceof IllegalConceptDescriptor;

      if (LOG.isInfoLevel()) {
        LOG.info("Refactoring starting...");
      }
      MoveNodesUtil.moveTo(project, "", MapSequence.fromMapAndEntryArray(new HashMap<MoveNodesUtil.NodeProcessor, List<SNode>>(), Map.entry(new MoveNodesUtil.NodeCreatingProcessor(new NodeLocation.NodeLocationRoot(getTargetModel()), project), ListSequence.fromListAndArray(new ArrayList<SNode>(), getConcept_A()))), new HeadlessRefactoringUI.OptionsChecker(expectedOptions));
      if (LOG.isInfoLevel()) {
        LOG.info("Refactoring finished");
      }
    });

    if (LOG.isInfoLevel()) {
      LOG.info("Check finished");
    }
  }
  @Test
  public void test_moveProperty_MPS_27700() throws Exception {
    commonTest((List<RefactoringParticipant.Option> options) -> {

      ListSequence.fromList(options).addElement(UpdateModelImports.OPTION);
      ListSequence.fromList(options).addElement(UpdateReferencesParticipantBase.UpdateReferencesParticipant.OPTION);


      ListSequence.fromList(options).addElement(LanguageStructureMigrationParticipant.OPTION);
    }, () -> {
      ConceptDescriptor conceptDescriptor = ConceptRegistry.getInstance().getConceptDescriptor(MetaAdapterByDeclaration.getConcept(getConcept_EnumPropertyContainer()));
      assert conceptDescriptor instanceof CompiledConceptDescriptor;
    }, (List<SNode> nodesToMove) -> ListSequence.fromList(nodesToMove).addElement(getProperty_MovedProperty()), () -> new MoveNodesUtil.NodeCreatingProcessor(new NodeLocation.NodeLocationChild(getConcept_PropertySupercontainer(), LINKS.propertyDeclaration$YUgg), project), () -> project.getRepository().getModelAccess().runReadAction(() -> {
      Iterable<SProperty> properties = getPropertyConceptInstance().getProperties();
      Assert.assertTrue(Sequence.fromIterable(properties).all((it) -> getPropertyConceptInstance().getConcept().getProperties().contains(it)));
      Assert.assertFalse(Sequence.fromIterable(properties).any((it) -> Objects.equals(it.getOwner().getSourceNode(), getConcept_PropertyContainer().getReference())));
      Assert.assertTrue(Sequence.fromIterable(properties).any((it) -> Objects.equals(it.getOwner().getSourceNode(), getConcept_PropertySupercontainer().getReference())));
    }));
  }
  @Test
  public void test_moveEnumProperty() throws Exception {
    commonTest((List<RefactoringParticipant.Option> options) -> {

      ListSequence.fromList(options).addElement(UpdateModelImports.OPTION);
      ListSequence.fromList(options).addElement(UpdateReferencesParticipantBase.UpdateReferencesParticipant.OPTION);


      ListSequence.fromList(options).addElement(LanguageStructureMigrationParticipant.OPTION);
    }, () -> {
      ConceptDescriptor conceptDescriptor = ConceptRegistry.getInstance().getConceptDescriptor(MetaAdapterByDeclaration.getConcept(getConcept_EnumPropertyContainer()));
      assert conceptDescriptor instanceof CompiledConceptDescriptor;
    }, (List<SNode> nodesToMove) -> ListSequence.fromList(nodesToMove).addElement(getProperty_MovedEnumProperty()), () -> new MoveNodesUtil.NodeCreatingProcessor(new NodeLocation.NodeLocationChild(getConcept_PropertySupercontainer(), LINKS.propertyDeclaration$YUgg), project), () -> project.getRepository().getModelAccess().runReadAction(() -> {
      Iterable<SProperty> properties = getEnumPropertyConceptInstance().getProperties();
      Assert.assertTrue(Sequence.fromIterable(properties).all((it) -> getEnumPropertyConceptInstance().getConcept().getProperties().contains(it)));
      Assert.assertFalse(Sequence.fromIterable(properties).any((it) -> Objects.equals(it.getOwner().getSourceNode(), getConcept_EnumPropertyContainer().getReference())));
      Assert.assertTrue(Sequence.fromIterable(properties).any((it) -> Objects.equals(it.getOwner().getSourceNode(), getConcept_PropertySupercontainer().getReference())));
    }));
  }
  @Test
  public void test_movedConceptHasCompletion_MPS27494() throws Exception {
    commonTest((List<RefactoringParticipant.Option> options) -> {
      ListSequence.fromList(options).addElement(UpdateModelImports.OPTION);
      ListSequence.fromList(options).addElement(UpdateReferencesParticipantBase.UpdateReferencesParticipant.OPTION);

      ListSequence.fromList(options).addElement(MoveAspectsParticipant.OPTION);
      ListSequence.fromList(options).addElement(WriteSubconceptMigrationParticipant.OPTION);

      ListSequence.fromList(options).addElement(LanguageStructureMigrationParticipant.OPTION);
    }, () -> {
      // do nothing
    }, (List<SNode> nodesToMove) -> ListSequence.fromList(nodesToMove).addElement(getConcept_TestCompletion()), () -> new MoveNodesUtil.NodeCreatingProcessor(new NodeLocation.NodeLocationRoot(getTargetModel()), project), () -> project.getRepository().getModelAccess().executeCommand(() -> {
      SNode instanceRoot = getInstanceTestCompletion();
      Assert.assertNotNull(instanceRoot);
      Assert.assertTrue(!(Objects.equals(SNodeOperations.getConcept(instanceRoot), SNodeOperations.asSConcept(getConcept_TestCompletion()))));
      Assert.assertTrue(ListSequence.fromList(SNodeOperations.getChildren(instanceRoot)).isEmpty());
      MPSNodeVirtualFile rootFile = NodeVirtualFileSystem.getInstance().getFileFor(project.getRepository(), instanceRoot);
      MPSFileNodeEditor fileNodeEditor = new MPSFileNodeEditor((MPSProject) project, rootFile);
      Editor nodeEditor = fileNodeEditor.getNodeEditor();
      nodeEditor.showNode(instanceRoot, false);
      NodeEditorComponent component = (NodeEditorComponent) nodeEditor.getCurrentEditorComponent();
      component.addNotify();
      component.setSize(component.getPreferredSize());
      component.validate();
      component.selectNode(instanceRoot, "empty_child");
      for (char keyTyped : "concept239".toCharArray()) {
        component.processKeyTyped(new KeyEvent(component, KeyEvent.KEY_TYPED, 0, 0, 0, keyTyped));
      }
      Assert.assertTrue(ListSequence.fromList(SNodeOperations.getChildren(instanceRoot)).count() == 1);
      Assert.assertTrue(Objects.equals(SNodeOperations.getConcept(ListSequence.fromList(SNodeOperations.getChildren(instanceRoot)).first()), SNodeOperations.getConcept(instanceRoot)));
    }));
  }

  public MoveConceptRefactoring_Test() {
    super(PROJECT_PATH);
  }

  public Collection<ReportItem> getErrors(Iterable<SNode> roots) {
    final List<ReportItem> result = ListSequence.fromList(new ArrayList<ReportItem>());
    ValidationUtil.runChecker(new StructureChecker().asRootChecker(), roots, this.project.getRepository(), new Processor<ReportItem>() {
      public boolean process(ReportItem problem) {
        ListSequence.fromList(result).addElement(problem);
        return true;
      }
    });
    return result;
  }

  public void runCommand(final Runnable runnable) {
    runTestInEDT(() -> project.getRepository().getModelAccess().executeCommand(() -> runnable.run()));
  }

  public void runTestInEDT(final Runnable runnable) {
    final Reference<Throwable> ref = new Reference();
    ThreadUtils.runInUIThreadAndWait(() -> {
      try {
        runnable.run();
      } catch (Throwable t) {
        ref.set(t);
      }
    });
    if (!(ref.isNull())) {
      throw new RuntimeException(ref.get());
    }
  }

  public SNode getConcept_A() {
    return SPointerOperations.resolveNode(new SNodePointer("r:469ff9d9-5a2e-4029-9891-ce478377a661(jetbrains.mps.refactoring.testmaterial.moveConcept.SourceLanguage.structure)", "6006982468244407213"), project.getRepository());
  }
  public SNode getConcept_B() {
    return SPointerOperations.resolveNode(new SNodePointer("r:469ff9d9-5a2e-4029-9891-ce478377a661(jetbrains.mps.refactoring.testmaterial.moveConcept.SourceLanguage.structure)", "1204068184860841"), project.getRepository());
  }
  public SNode getConcept_TestCompletion() {
    return SPointerOperations.resolveNode(new SNodePointer("r:469ff9d9-5a2e-4029-9891-ce478377a661(jetbrains.mps.refactoring.testmaterial.moveConcept.SourceLanguage.structure)", "4662087456932171631"), project.getRepository());
  }
  public SNode getConcept_PropertyContainer() {
    return SPointerOperations.resolveNode(new SNodePointer("r:469ff9d9-5a2e-4029-9891-ce478377a661(jetbrains.mps.refactoring.testmaterial.moveConcept.SourceLanguage.structure)", "493339661774729917"), project.getRepository());
  }
  public SNode getConcept_EnumPropertyContainer() {
    return SPointerOperations.resolveNode(new SNodePointer("r:469ff9d9-5a2e-4029-9891-ce478377a661(jetbrains.mps.refactoring.testmaterial.moveConcept.SourceLanguage.structure)", "8831258047753184794"), project.getRepository());
  }
  public SNode getConcept_PropertySupercontainer() {
    return SPointerOperations.resolveNode(new SNodePointer("r:469ff9d9-5a2e-4029-9891-ce478377a661(jetbrains.mps.refactoring.testmaterial.moveConcept.SourceLanguage.structure)", "493339661774729923"), project.getRepository());
  }
  public SNode getConcept_PropertyInstance() {
    return SPointerOperations.resolveNode(new SNodePointer("r:469ff9d9-5a2e-4029-9891-ce478377a661(jetbrains.mps.refactoring.testmaterial.moveConcept.SourceLanguage.structure)", "493339661774729920"), project.getRepository());
  }
  public SNode getProperty_MovedProperty() {
    return SPointerOperations.resolveNode(new SNodePointer("r:469ff9d9-5a2e-4029-9891-ce478377a661(jetbrains.mps.refactoring.testmaterial.moveConcept.SourceLanguage.structure)", "493339661774729918"), project.getRepository());
  }
  public SNode getProperty_MovedEnumProperty() {
    return SPointerOperations.resolveNode(new SNodePointer("r:469ff9d9-5a2e-4029-9891-ce478377a661(jetbrains.mps.refactoring.testmaterial.moveConcept.SourceLanguage.structure)", "8831258047753006375"), project.getRepository());
  }
  public SNode getInstanceA() {
    return SPointerOperations.resolveNode(new SNodePointer("r:ac08359f-193b-493f-92ef-48848aecee7b(jetbrains.mps.refactoring.testmaterial.moveConcept.InstanceSolution.main)", "6006982468244420385"), project.getRepository());
  }
  public SNode getInstanceB() {
    return SPointerOperations.resolveNode(new SNodePointer("r:ac08359f-193b-493f-92ef-48848aecee7b(jetbrains.mps.refactoring.testmaterial.moveConcept.InstanceSolution.main)", "1204068184864697"), project.getRepository());
  }
  public SNode getPropertyConceptInstance() {
    return SPointerOperations.resolveNode(new SNodePointer("r:ac08359f-193b-493f-92ef-48848aecee7b(jetbrains.mps.refactoring.testmaterial.moveConcept.InstanceSolution.main)", "493339661776050901"), project.getRepository());
  }
  public SNode getEnumPropertyConceptInstance() {
    return SPointerOperations.resolveNode(new SNodePointer("r:ac08359f-193b-493f-92ef-48848aecee7b(jetbrains.mps.refactoring.testmaterial.moveConcept.InstanceSolution.main)", "8831258047753333951"), project.getRepository());
  }
  public SNode getInstanceTestCompletion() {
    return SPointerOperations.resolveNode(new SNodePointer("r:ac08359f-193b-493f-92ef-48848aecee7b(jetbrains.mps.refactoring.testmaterial.moveConcept.InstanceSolution.main)", "4662087456932179903"), project.getRepository());
  }
  public SModel getTargetModel() {
    SModule targetModule = PersistenceFacade.getInstance().createModuleReference("2f6eb168-4811-48ad-becb-56fd47d21d59(testmaterial.moveConcept.TargetLanguage)").resolve(project.getRepository());
    Assert.assertNotNull(targetModule);
    return SModuleOperations.getAspect(targetModule, "structure");
  }


  public void commonTest(final _FunctionTypes._void_P1_E0<? super List<RefactoringParticipant.Option>> setOptions, final _FunctionTypes._void_P0_E0 prepareNodes, final _FunctionTypes._void_P1_E0<? super List<SNode>> setNodesToMove, final _FunctionTypes._return_P0_E0<? extends MoveNodesUtil.NodeProcessor> nodeProcessor, final _FunctionTypes._void_P0_E0 additionalCheck) {
    // cleaning class files to make test behavior determinate:
    // local execution might have .class filess copied from project
    // on the buildserver there are no .class files
    runCommand(() -> {
      if (LOG.isInfoLevel()) {
        LOG.info("Cleaning generated classes...");
      }
      List<SModule> projectModules = project.getProjectModules();
      ListSequence.fromList(projectModules).translate((it) -> it.getModels()).visitAll((it) -> new ModelDeleteHelper(it).removeGeneratedArtifacts());
      ApplicationManager.getApplication().getComponent(MPSCoreComponents.class).getClassLoaderManager().reloadModules(projectModules);
      Iterable<LanguageRuntime> projectLanguages = ListSequence.fromList(projectModules).ofType(Language.class).select((it) -> LanguageRegistry.getInstance(project.getRepository()).getLanguage(it));
      // this is a hack needed to clear global registry to unload languages like no languages were loaded at all
      ConceptRegistry.getInstance().afterLanguagesLoaded(projectLanguages);
    });
    doMake(project.getProjectModulesWithGenerators(), true);
    // this is not formally correct to store SModule, but ok for testing purposes
    final Wrappers._T<SModule> sourceModule = new Wrappers._T<SModule>();
    final Wrappers._T<SModule> targetModule = new Wrappers._T<SModule>();
    project.getRepository().getModelAccess().runReadAction(() -> {
      sourceModule.value = PersistenceFacade.getInstance().createModuleReference("3e00419d-4801-4bad-bf2a-50479218fb53(testmaterial.moveConcept.SourceLanguage)").resolve(project.getRepository());
      Assert.assertNotNull(sourceModule.value);
      targetModule.value = PersistenceFacade.getInstance().createModuleReference("2f6eb168-4811-48ad-becb-56fd47d21d59(testmaterial.moveConcept.TargetLanguage)").resolve(project.getRepository());
      Assert.assertNotNull(targetModule.value);
      SModel targetModel = SModuleOperations.getAspect(targetModule.value, "structure");
      Assert.assertNotNull(targetModel);
      Assert.assertNotNull(getConcept_A());
      Assert.assertNotNull(getConcept_B());
      Assert.assertNotNull(getInstanceA());
      Assert.assertNotNull(getInstanceB());
    });

    final List<RefactoringParticipant.Option> options = ListSequence.fromList(new ArrayList<RefactoringParticipant.Option>());
    setOptions.invoke(options);
    runCommand(() -> {
      prepareNodes.invoke();
      if (LOG.isInfoLevel()) {
        LOG.info("Refactoring starting...");
      }
      List<SNode> nodesToMove = ListSequence.fromList(new ArrayList<SNode>());
      setNodesToMove.invoke(nodesToMove);
      MoveNodesUtil.moveTo(project, "", MapSequence.fromMapAndEntryArray(new HashMap<MoveNodesUtil.NodeProcessor, List<SNode>>(), Map.entry(nodeProcessor.invoke(), nodesToMove)), new HeadlessRefactoringUI(options));
      if (LOG.isInfoLevel()) {
        LOG.info("Refactoring finished");
      }
    });
    // not really needed, but still let's end the transaction before checking

    if (LOG.isInfoLevel()) {
      LOG.info("Checking for errors after refactoring...");
    }
    project.getRepository().getModelAccess().runReadAction(() -> {
      Collection<ReportItem> sourceErrors = getErrors(SModelOperations.roots(SModuleOperations.getAspect(sourceModule.value, "constraints"), null));
      Assert.assertTrue("" + sourceErrors, CollectionSequence.fromCollection(sourceErrors).isEmpty());
      Collection<ReportItem> targetErrors = getErrors(SModelOperations.roots(SModuleOperations.getAspect(targetModule.value, "constraints"), null));
      Assert.assertTrue("" + targetErrors, CollectionSequence.fromCollection(targetErrors).isEmpty());
    });
    if (LOG.isInfoLevel()) {
      LOG.info("Checking finished");
    }

    if (LOG.isInfoLevel()) {
      LOG.info("Making newly created migrations...");
    }
    doMake(ListSequence.fromListAndArray(new ArrayList<SModule>(), sourceModule.value, targetModule.value), false);

    if (LOG.isInfoLevel()) {
      LOG.info("Migrating...");
    }

    ApplicationManager.getApplication().invokeAndWait(() -> {
      try {
        AntTaskExecutionUtil.migrate(project, true, true);
      } catch (Exception e) {
        throw new RuntimeException("Exception during migration", e);
      }
    }, ModalityState.defaultModalityState());
    if (LOG.isInfoLevel()) {
      LOG.info("Migration finished");
    }

    if (LOG.isInfoLevel()) {
      LOG.info("Checking migration results...");
    }
    runTestInEDT(() -> additionalCheck.invoke());
    if (LOG.isInfoLevel()) {
      LOG.info("Check finished");
    }
  }

  private static final class LINKS {
    /*package*/ static final SContainmentLink propertyDeclaration$YUgg = MetaAdapterFactory.getContainmentLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103553c5ffL, 0xf979c3ba6cL, "propertyDeclaration");
  }
}
