/* * Copyright (c) 2013, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.ui.refactoring; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.dart.engine.services.change.Change; import com.google.dart.engine.services.change.CompositeChange; import com.google.dart.engine.services.change.Edit; import com.google.dart.engine.services.change.MergeCompositeChange; import com.google.dart.engine.services.change.SourceChange; import com.google.dart.engine.services.correction.ChangeCorrectionProposal; import com.google.dart.engine.services.correction.CorrectionImage; import com.google.dart.engine.services.correction.CorrectionKind; import com.google.dart.engine.services.correction.CorrectionProposal; import com.google.dart.engine.services.correction.LinkedPositionProposal; import com.google.dart.engine.services.correction.SourceCorrectionProposal; import com.google.dart.engine.services.status.RefactoringStatus; import com.google.dart.engine.source.FileBasedSource; import com.google.dart.engine.source.Source; import com.google.dart.engine.utilities.io.FileUtilities2; import com.google.dart.engine.utilities.source.SourceRange; import com.google.dart.tools.core.refactoring.CompilationUnitChange; import com.google.dart.tools.internal.corext.refactoring.util.ReflectionUtils; import com.google.dart.tools.ui.internal.refactoring.ServiceUtils_OLD; import com.google.dart.tools.ui.internal.text.correction.proposals.LinkedCorrectionProposal_OLD; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.ltk.core.refactoring.TextEditBasedChangeGroup; import org.eclipse.ltk.core.refactoring.TextFileChange; import org.eclipse.text.edits.MultiTextEdit; import org.eclipse.text.edits.ReplaceEdit; import org.eclipse.text.edits.TextEdit; import static org.fest.assertions.Assertions.assertThat; import java.io.File; import java.util.List; import java.util.Map; /** * Test for {@link ServiceUtils_OLD}. */ public class ServiceUtilsTest extends AbstractDartTest { private final IProgressMonitor NULL_PM = new NullProgressMonitor(); public void test_createCoreException() throws Exception { Throwable e = new Throwable("msg"); CoreException coreException = ServiceUtils_OLD.createCoreException(e); assertSame(e, coreException.getCause()); // status IStatus status = coreException.getStatus(); assertSame(e, status.getException()); assertSame(IStatus.ERROR, status.getSeverity()); } public void test_toLTK_Change_CompositeChange() throws Exception { Source source = createTestFileSource(); // fill SourceChange SourceChange sourceChangeA = new SourceChange("My change A", source); SourceChange sourceChangeB = new SourceChange("My change B", source); CompositeChange compositeChange = new CompositeChange( "My composite change", sourceChangeA, sourceChangeB); // toLTK org.eclipse.ltk.core.refactoring.Change ltkChange_ = ServiceUtils_OLD.toLTK(compositeChange); org.eclipse.ltk.core.refactoring.CompositeChange ltkChange = (org.eclipse.ltk.core.refactoring.CompositeChange) ltkChange_; assertEquals("My composite change", ltkChange.getName()); org.eclipse.ltk.core.refactoring.Change[] ltkChanges = ltkChange.getChildren(); assertThat(ltkChanges).hasSize(2); } public void test_toLTK_Change_CompositeChange_noFile() throws Exception { Source source = new FileBasedSource(new File("no-such-file.dart")); SourceChange sourceChangeA = new SourceChange("My change A", source); SourceChange sourceChangeB = new SourceChange("My change B", source); CompositeChange compositeChange = new CompositeChange( "My composite change", sourceChangeA, sourceChangeB); // toLTK org.eclipse.ltk.core.refactoring.Change ltkChange_ = ServiceUtils_OLD.toLTK(compositeChange); org.eclipse.ltk.core.refactoring.CompositeChange ltkChange = (org.eclipse.ltk.core.refactoring.CompositeChange) ltkChange_; assertEquals("My composite change", ltkChange.getName()); org.eclipse.ltk.core.refactoring.Change[] ltkChanges = ltkChange.getChildren(); assertThat(ltkChanges).isEmpty(); } public void test_toLTK_Change_MergeCompositeChange() throws Exception { IFile testFile = testProject.setFileContent("test.dart", "012345"); Source source = createFileSource(testFile); // fill SourceChange SourceChange sourceChangeA = new SourceChange("My change A", source); SourceChange sourceChangeB = new SourceChange("My change B", source); sourceChangeA.addEdit(new Edit(0, 0, "a")); sourceChangeB.addEdit(new Edit(2, 0, "b")); CompositeChange compositeChangeA = new CompositeChange("A", sourceChangeA); CompositeChange compositeChangeB = new CompositeChange("B", sourceChangeB); MergeCompositeChange mergeChange = new MergeCompositeChange( "My composite change", compositeChangeA, compositeChangeB); // toLTK org.eclipse.ltk.core.refactoring.Change ltkChange_ = ServiceUtils_OLD.toLTK(mergeChange); org.eclipse.ltk.core.refactoring.CompositeChange ltkChange = (org.eclipse.ltk.core.refactoring.CompositeChange) ltkChange_; assertEquals("My composite change", ltkChange.getName()); org.eclipse.ltk.core.refactoring.Change[] ltkChanges = ltkChange.getChildren(); assertThat(ltkChanges).hasSize(2); // ltkChange.perform(NULL_PM); String newContent = testProject.getFileString(testFile); assertEquals("a01b2345", newContent); } public void test_toLTK_Change_MergeCompositeChange_emptyPreview() throws Exception { IFile testFile = testProject.setFileContent("test.dart", "012345"); Source source = createFileSource(testFile); // fill SourceChange SourceChange sourceChangeB = new SourceChange("My change B", source); sourceChangeB.addEdit(new Edit(2, 0, "b")); CompositeChange compositeChangeA = new CompositeChange("A"); CompositeChange compositeChangeB = new CompositeChange("B", sourceChangeB); MergeCompositeChange mergeChange = new MergeCompositeChange( "My composite change", compositeChangeA, compositeChangeB); // toLTK org.eclipse.ltk.core.refactoring.Change ltkChange_ = ServiceUtils_OLD.toLTK(mergeChange); org.eclipse.ltk.core.refactoring.CompositeChange ltkChange = (org.eclipse.ltk.core.refactoring.CompositeChange) ltkChange_; assertEquals("My composite change", ltkChange.getName()); org.eclipse.ltk.core.refactoring.Change[] ltkChanges = ltkChange.getChildren(); assertThat(ltkChanges).hasSize(1); assertThat(ltkChanges[0]).isInstanceOf(CompilationUnitChange.class); } public void test_toLTK_Change_SourceChange() throws Exception { Source source = createTestFileSource(); // fill SourceChange SourceChange sourceChange = new SourceChange("My change", source); sourceChange.addEdit(new Edit(10, 1, "a")); sourceChange.addEdit(new Edit(20, 2, "b")); // toLTK TextFileChange ltkChange = (TextFileChange) ServiceUtils_OLD.toLTK((Change) sourceChange); assertEquals("My change", ltkChange.getName()); } public void test_toLTK_Change_SourceChange_externalFile() throws Exception { Source source = new FileBasedSource(FileUtilities2.createFile("/some/path")); // fill SourceChange SourceChange sourceChange = new SourceChange("My change", source); sourceChange.addEdit(new Edit(10, 1, "a")); sourceChange.addEdit(new Edit(20, 2, "b")); // no IFile for this Source, so no LTK change { org.eclipse.ltk.core.refactoring.Change ltkChange = ServiceUtils_OLD.toLTK(sourceChange); assertNull(ltkChange); } // try as part of CompositeChange { CompositeChange compositeChange = new CompositeChange("My composite change", sourceChange); org.eclipse.ltk.core.refactoring.CompositeChange ltkChange = ServiceUtils_OLD.toLTK(compositeChange); assertNotNull(ltkChange); // wrong SourceChange was ignored assertThat(ltkChange.getChildren()).isEmpty(); } } public void test_toLTK_CorrectionImage() throws Exception { assertNotNull(ServiceUtils_OLD.toLTK(CorrectionImage.IMG_CORRECTION_CHANGE)); assertNotNull(ServiceUtils_OLD.toLTK(CorrectionImage.IMG_CORRECTION_CLASS)); } public void test_toLTK_RefactoringStatus() throws Exception { RefactoringStatus serviceStatus = RefactoringStatus.createErrorStatus("msg"); org.eclipse.ltk.core.refactoring.RefactoringStatus ltkStatus = ServiceUtils_OLD.toLTK(serviceStatus); org.eclipse.ltk.core.refactoring.RefactoringStatusEntry[] ltkEntries = ltkStatus.getEntries(); assertThat(ltkEntries).hasSize(1); // entry[0] assertEquals("msg", ltkEntries[0].getMessage()); assertEquals( org.eclipse.ltk.core.refactoring.RefactoringStatus.ERROR, ltkEntries[0].getSeverity()); } public void test_toLTK_SourceChange_noGroups() throws Exception { Source source = createTestFileSource(); // fill SourceChange SourceChange sourceChange = new SourceChange("My change", source); sourceChange.addEdit(new Edit(10, 1, "a")); sourceChange.addEdit(new Edit(20, 2, "b")); // toLTK TextFileChange ltkChange = ServiceUtils_OLD.toLTK(sourceChange); assertEquals("My change", ltkChange.getName()); // no groups TextEditBasedChangeGroup[] changeGroups = ltkChange.getChangeGroups(); assertThat(changeGroups).isEmpty(); // check edits MultiTextEdit multiTextEdit = (MultiTextEdit) ltkChange.getEdit(); TextEdit[] textEdits = multiTextEdit.getChildren(); assertThat(textEdits).hasSize(2); assertEquals("a", ((ReplaceEdit) textEdits[0]).getText()); assertEquals("b", ((ReplaceEdit) textEdits[1]).getText()); } /** * It is OK to apply more than one insert {@link Edit} with the same offset. * <p> * For example Quick Fix "Implement Missing Overrides" inserts several method declarations. */ public void test_toLTK_SourceChange_twoInserts() throws Exception { Source source = createTestFileSource(); // fill SourceChange SourceChange sourceChange = new SourceChange("My change", source); sourceChange.addEdit(new Edit(2, 0, "a")); sourceChange.addEdit(new Edit(2, 0, "b")); // toLTK TextFileChange ltkChange = ServiceUtils_OLD.toLTK(sourceChange); TextEdit textEdit = ltkChange.getEdit(); // apply Document document = new Document("01234"); textEdit.apply(document); assertEquals("01ab234", document.get()); } public void test_toLTK_SourceChange_withGroups() throws Exception { Source source = createTestFileSource(); // fill SourceChange SourceChange sourceChange = new SourceChange("My change", source); sourceChange.addEdit(new Edit(10, 1, "a1"), "groupA"); sourceChange.addEdit(new Edit(20, 2, "a2"), "groupA"); sourceChange.addEdit(new Edit(30, 3, "b"), "groupB"); // toLTK TextFileChange ltkChange = ServiceUtils_OLD.toLTK(sourceChange); assertEquals("My change", ltkChange.getName()); TextEditBasedChangeGroup[] changeGroups = ltkChange.getChangeGroups(); assertThat(changeGroups).hasSize(2); { TextEditBasedChangeGroup group = changeGroups[0]; assertEquals("groupA", group.getName()); TextEdit[] textEdits = group.getTextEdits(); assertThat(textEdits).hasSize(2); assertEquals("a1", ((ReplaceEdit) textEdits[0]).getText()); assertEquals("a2", ((ReplaceEdit) textEdits[1]).getText()); } } public void test_toLTK_Throwable() throws Exception { Throwable e = new Throwable("msg"); org.eclipse.ltk.core.refactoring.RefactoringStatus ltkStatus = ServiceUtils_OLD.toLTK(e); org.eclipse.ltk.core.refactoring.RefactoringStatusEntry[] ltkEntries = ltkStatus.getEntries(); assertThat(ltkEntries).hasSize(1); // entry[0] assertEquals("msg", ltkEntries[0].getMessage()); assertEquals( org.eclipse.ltk.core.refactoring.RefactoringStatus.FATAL, ltkEntries[0].getSeverity()); } public void test_toUI_ChangeCorrectionProposal() throws Exception { Source source = createTestFileSource(); // fill SourceChange SourceChange sourceChange = new SourceChange("My change", source); sourceChange.addEdit(new Edit(10, 1, "a")); sourceChange.addEdit(new Edit(20, 1, "a")); sourceChange.addEdit(new Edit(30, 3, "b")); // create ChangeCorrectionProposal CorrectionProposal proposal = new ChangeCorrectionProposal( sourceChange, CorrectionKind.QA_ADD_TYPE_ANNOTATION); // com.google.dart.tools.ui.internal.text.correction.proposals.ChangeCorrectionProposal uiProposal = (com.google.dart.tools.ui.internal.text.correction.proposals.ChangeCorrectionProposal) ServiceUtils_OLD.toUI(proposal); ReflectionUtils.invokeMethod(uiProposal, "getChange()"); CompilationUnitChange ltkChange = (CompilationUnitChange) uiProposal.getChange(); assertEquals("My change", ltkChange.getName()); } public void test_toUI_ChangeCorrectionProposal_noFile() throws Exception { Source source = new FileBasedSource(new File("no-such-file.dart")); SourceChange sourceChange = new SourceChange("My change", source); CorrectionProposal proposal = new ChangeCorrectionProposal( sourceChange, CorrectionKind.QA_ADD_TYPE_ANNOTATION); ICompletionProposal uiProposal = ServiceUtils_OLD.toUI(proposal); assertNull(uiProposal); } public void test_toUI_LinkedCorrectionProposal() throws Exception { Source source = createTestFileSource(); // fill SourceChange SourceChange sourceChange = new SourceChange("My linked change", source); sourceChange.addEdit(new Edit(10, 1, "a")); sourceChange.addEdit(new Edit(20, 1, "a")); sourceChange.addEdit(new Edit(30, 3, "b")); // create SourceCorrectionProposal SourceCorrectionProposal proposal = new SourceCorrectionProposal( sourceChange, CorrectionKind.QA_ADD_TYPE_ANNOTATION); { List<SourceRange> ranges = ImmutableList.of(new SourceRange(10, 1), new SourceRange(20, 1)); Map<String, List<SourceRange>> linkedPositons = ImmutableMap.of("a", ranges); proposal.setLinkedPositions(linkedPositons); } { List<LinkedPositionProposal> proposals = ImmutableList.of(new LinkedPositionProposal( CorrectionImage.IMG_CORRECTION_CHANGE, "proposalA")); Map<String, List<LinkedPositionProposal>> linkedProposals = ImmutableMap.of("a", proposals); proposal.setLinkedPositionProposals(linkedProposals); } // LinkedCorrectionProposal_OLD uiProposal = ServiceUtils_OLD.toUI(proposal); CompilationUnitChange ltkChange = (CompilationUnitChange) uiProposal.getChange(); assertEquals("My linked change", ltkChange.getName()); } public void test_toUI_LinkedCorrectionProposal_noFile() throws Exception { Source source = new FileBasedSource(new File("no-such-file.dart")); SourceChange sourceChange = new SourceChange("My change", source); SourceCorrectionProposal proposal = new SourceCorrectionProposal( sourceChange, CorrectionKind.QA_ADD_TYPE_ANNOTATION); LinkedCorrectionProposal_OLD uiProposal = ServiceUtils_OLD.toUI(proposal); assertNull(uiProposal); } /** * @return the {@link Source} for the given {@link IFile}. */ private Source createFileSource(IFile file) { File ioFile = file.getLocation().toFile(); return new FileBasedSource(ioFile); } /** * @return the {@link Source} for <code>test.dart</code> file. */ private Source createTestFileSource() throws Exception { IFile testFile = testProject.setFileContent("test.dart", ""); return createFileSource(testFile); } }