package com.sap.ide.refactoring.dependencies; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.antlr.runtime.Lexer; import org.junit.Test; import tcs.ClassTemplate; import tcs.ConcreteSyntax; import textblocks.TextBlock; import textblocks.TextblocksPackage; import com.sap.ide.cts.editor.EditorUtil; import com.sap.ide.cts.editor.prettyprint.imported.PrettyPrinter; import com.sap.ide.cts.editor.prettyprint.imported.SyntaxAndModelMismatchException; import com.sap.ide.cts.editor.prettyprint.textblocks.IncrementalTextBlockPrettyPrinter; import com.sap.ide.cts.editor.prettyprint.textblocks.TextBlockTCSExtractorStream; import com.sap.ide.cts.moin.parserfactory.AbstractParserFactory; import com.sap.ide.refactoring.core.textual.RefactoringEditorFacade; import com.sap.ide.refactoring.test.RefactoringBaseTest; import com.sap.mi.textual.grammar.impl.ObservableInjectingParser; import com.sap.mi.textual.parsing.textblocks.TbValidationUtil; import com.sap.tc.moin.repository.mmi.reflect.RefObject; import data.classes.SapClass; /** * We had difficulties undoing incremental pretty printer runs. * * There must be a combination of actions that MOIN has difficulties with. The following tests * were used to track the issue down. * * It works now after making a few changes to {@link CtsTextBlockIncrementalTCSExtractorStream}. * Unfortunately I don't know why... :-/ * */ public class TestMoinCommandStack extends RefactoringBaseTest { @Test public void testUndoOfOrderdCompositeAssociationInCommand() { TextblocksPackage tbPackage = connection.getPackage(TextblocksPackage.PACKAGE_DESCRIPTOR); TextBlock parentBlock = (TextBlock) tbPackage.getTextBlock().refCreateInstance(); createTextBlocksInCommand(parentBlock); // Pre undo order check for (int i=0; i<parentBlock.getSubBlocks().size(); i++) { assertEquals(i, parentBlock.getSubBlocks().get(i).getOffset()); } connection.getCommandStack().undo(); assertTrue("SubBlocks should all be gone by the undo", parentBlock.getSubBlocks().isEmpty()); connection.getCommandStack().redo(); // Post undo order check for (int i=0; i<parentBlock.getSubBlocks().size(); i++) { assertEquals(i, parentBlock.getSubBlocks().get(i).getOffset()); } } private void createTextBlocksInCommand(TextBlock parentBlock) { TextblocksPackage tbPackage = connection.getPackage(TextblocksPackage.PACKAGE_DESCRIPTOR); connection.getCommandStack().openGroup("Create Sub TextBlocks"); TextBlock leftSubBlock = (TextBlock) tbPackage.getTextBlock().refCreateInstance(); leftSubBlock.setOffset(0); leftSubBlock.setParentBlock(parentBlock); TextBlock middleSubBlock = (TextBlock) tbPackage.getTextBlock().refCreateInstance(); middleSubBlock.setOffset(1); middleSubBlock.setParentBlock(parentBlock); TextBlock rightSubBlock = (TextBlock) tbPackage.getTextBlock().refCreateInstance(); rightSubBlock.setOffset(2); rightSubBlock.setParentBlock(parentBlock); connection.getCommandStack().closeGroup(); } @Test public void testUndoPrettyPrinting() { RefactoringEditorFacade facade = createEditorFacadeForRunletClass("Class2"); TextBlock textBlockToPrint = facade.getTextBlocksModel().getRoot(); SapClass correspondingModelElement = (SapClass) facade.getDecoratedDomainRootObject(); // TB needs to be valid before we start the refactoring. TbValidationUtil.assertTextBlockConsistencyRecursive(textBlockToPrint); connection.getCommandStack().openGroup("Pretty Print"); TextBlock newRootTextBlock = prettyPrint(textBlockToPrint, correspondingModelElement); connection.getCommandStack().closeGroup(); TbValidationUtil.assertTextBlockConsistencyRecursive(newRootTextBlock); TbValidationUtil.assertTextBlockConsistencyRecursive(textBlockToPrint); connection.getCommandStack().undo(); // We have just undone the refactoring. It is essential that we still have a valid TB. TbValidationUtil.assertTextBlockConsistencyRecursive(textBlockToPrint); } private TextBlock prettyPrint(TextBlock textBlockToPrint, RefObject correspondingModelElement) { ClassTemplate template = (ClassTemplate) textBlockToPrint.getType().getParseRule(); ConcreteSyntax syntax = template.getConcretesyntax(); AbstractParserFactory<? extends ObservableInjectingParser, ? extends Lexer> parserFactory = EditorUtil .constructParserFactoryForSyntax(syntax); TextblocksPackage tbPackage = connection.getPackage(TextblocksPackage.PACKAGE_DESCRIPTOR); TextBlockTCSExtractorStream stream = new TextBlockTCSExtractorStream(tbPackage, textBlockToPrint.get___Partition(), parserFactory); try { PrettyPrinter prettyPrinter = new PrettyPrinter(); prettyPrinter.prettyPrint(correspondingModelElement, syntax, stream, template); } catch (SyntaxAndModelMismatchException e) { fail(e.getMessage()); } return stream.getPrintedResultRootBlock(); } @Test public void testUndoIncrementalPrettyPrintingWithReuse() { RefactoringEditorFacade facade = createEditorFacadeForRunletClass("Class2"); TextBlock textBlockToPrint = facade.getTextBlocksModel().getRoot(); SapClass correspondingModelElement = (SapClass) facade.getDecoratedDomainRootObject(); // TB needs to be valid before we start the refactoring. TbValidationUtil.assertTextBlockConsistencyRecursive(textBlockToPrint); connection.getCommandStack().openGroup("Pretty Print"); TextBlock newRootTextBlock = incrementalPrettyPrint(textBlockToPrint, correspondingModelElement); connection.getCommandStack().closeGroup(); TbValidationUtil.assertTextBlockConsistencyRecursive(newRootTextBlock); connection.getCommandStack().undo(); // We have just undone the refactoring. It is essential that we still have a valid, original TB TbValidationUtil.assertTextBlockConsistencyRecursive(textBlockToPrint); } private TextBlock incrementalPrettyPrint(TextBlock textBlockToPrint, RefObject correspondingModelElement) { IncrementalTextBlockPrettyPrinter incrementalPrettyPrinter = new IncrementalTextBlockPrettyPrinter(); ClassTemplate template = (ClassTemplate) textBlockToPrint.getType().getParseRule(); ConcreteSyntax syntax = template.getConcretesyntax(); AbstractParserFactory<? extends ObservableInjectingParser, ? extends Lexer> parserFactory = EditorUtil.constructParserFactoryForSyntax(syntax); TextblocksPackage tbPackage = connection.getPackage(TextblocksPackage.PACKAGE_DESCRIPTOR); TextBlockTCSExtractorStream stream = new TextBlockTCSExtractorStream(tbPackage, textBlockToPrint.get___Partition(), parserFactory); try { incrementalPrettyPrinter.prettyPrint(correspondingModelElement, textBlockToPrint, syntax, template, stream); } catch (SyntaxAndModelMismatchException e) { fail(e.getMessage()); } return stream.getPrintedResultRootBlock(); } }