/* * 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.engine.services.internal.refactoring; import com.google.common.base.Objects; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.context.AnalysisContext; import com.google.dart.engine.index.Index; import com.google.dart.engine.index.IndexFactory; import com.google.dart.engine.index.IndexStore; import com.google.dart.engine.internal.index.file.MemoryNodeManager; import com.google.dart.engine.search.SearchEngine; import com.google.dart.engine.search.SearchEngineFactory; import com.google.dart.engine.services.change.Change; import com.google.dart.engine.services.change.CompositeChange; import com.google.dart.engine.services.change.CreateFileChange; 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.internal.correction.AbstractDartTest; import com.google.dart.engine.services.internal.correction.CorrectionUtils; import com.google.dart.engine.services.refactoring.NullProgressMonitor; import com.google.dart.engine.services.refactoring.ProgressMonitor; import com.google.dart.engine.services.refactoring.Refactoring; import com.google.dart.engine.services.refactoring.RenameRefactoring; import com.google.dart.engine.services.status.RefactoringStatusSeverity; import com.google.dart.engine.source.Source; import java.util.List; /** * Abstract test for testing {@link RenameRefactoring}s. */ public abstract class RefactoringImplTest extends AbstractDartTest { /** * Assert result of applying given {@link Change} to the "source". */ public static void assertChangeResult(AnalysisContext context, Change compositeChange, Source source, String expected) throws Exception { SourceChange sourceChange = getSourceChange(compositeChange, source); assertNotNull("No change for: " + source.toString(), sourceChange); String sourceResult = getChangeResult(context, source, sourceChange); assertEquals(expected, sourceResult); } /** * Asserts that "refactoring" status is OK. */ public static void assertRefactoringStatusOK(RenameRefactoring refactoring) throws Exception { ProgressMonitor pm = new NullProgressMonitor(); assertRefactoringStatus( refactoring.checkInitialConditions(pm), RefactoringStatusSeverity.OK, null); assertRefactoringStatus( refactoring.checkFinalConditions(pm), RefactoringStatusSeverity.OK, null); } /** * @return the {@link CreateFileChange} for the file with the given name (not full path). */ public static CreateFileChange findCreateFileChange(Change change, String fileName) { if (change instanceof CreateFileChange) { CreateFileChange fileChange = (CreateFileChange) change; if (fileChange.getFile().getName().equals(fileName)) { return fileChange; } } if (change instanceof CompositeChange) { CompositeChange compositeChange = (CompositeChange) change; for (Change childChange : compositeChange.getChildren()) { CreateFileChange fileChange = findCreateFileChange(childChange, fileName); if (fileChange != null) { return fileChange; } } } return null; } /** * @return the {@link SourceChange} for the given {@link Source}. */ protected static SourceChange getSourceChange(Change change, Source source) { // may be SourceChange if (change instanceof SourceChange) { SourceChange sourceChange = (SourceChange) change; if (Objects.equal(sourceChange.getSource(), source)) { return sourceChange; } } // may be MergeCompositeChange if (change instanceof MergeCompositeChange) { MergeCompositeChange mergeChange = (MergeCompositeChange) change; SourceChange executeChange = getSourceChange(mergeChange.getExecuteChange(), source); SourceChange previewChange = getSourceChange(mergeChange.getPreviewChange(), source); if (executeChange != null && previewChange == null) { return executeChange; } if (executeChange == null && previewChange != null) { return previewChange; } return mergeSourceChanges(executeChange, previewChange); } // may be CompositeChange if (change instanceof CompositeChange) { CompositeChange compositeChange = (CompositeChange) change; for (Change child : compositeChange.getChildren()) { SourceChange sourceChange = getSourceChange(child, source); if (sourceChange != null) { return sourceChange; } } } // not found return null; } /** * @return the result of applying given {@link SourceChange} to the {@link #testCode}. */ private static String getChangeResult(AnalysisContext context, Source source, SourceChange change) throws Exception { String sourceCode = CorrectionUtils.getSourceContent(context, source); List<Edit> sourceEdits = change.getEdits(); return CorrectionUtils.applyReplaceEdits(sourceCode, sourceEdits); } /** * Returns new {@link SourceChange} that consists of the merged {@link Edit}s from the given * {@link SourceChange}. Note, that edit groups are not supported. */ private static SourceChange mergeSourceChanges(SourceChange executeChange, SourceChange previewChange) { List<Edit> edits = executeChange.getEdits(); List<Edit> edits2 = previewChange.getEdits(); SourceChange merged = new SourceChange(executeChange.getName(), executeChange.getSource()); for (Edit edit : edits) { merged.addEdit(edit); } for (Edit edit : edits2) { merged.addEdit(edit); } return merged; } protected final ProgressMonitor pm = new NullProgressMonitor(); protected Index index; protected SearchEngine searchEngine; /** * Assert result of applying given {@link Change} to the given {@link Source}. */ protected final void assertChangeResult(Change compositeChange, Source source, String expected) throws Exception { AnalysisContext context = getAnalysisContext(); assertChangeResult(context, compositeChange, source, expected); } /** * Assert result of applying given {@link Change} to the {@link #testCode}. */ protected final void assertTestChangeResult(Change compositeChange, String expected) throws Exception { assertChangeResult(compositeChange, testSource, expected); } /** * Resolve and index the given source. */ protected final void indexTestUnit(Source source) throws Exception { parseTestUnit(source); AnalysisContext context = testUnit.getElement().getContext(); index.indexUnit(context, testUnit); } /** * Parses and index given source lines. */ protected final void indexTestUnit(String... lines) throws Exception { parseTestUnit(lines); AnalysisContext context = testUnit.getElement().getContext(); index.indexUnit(context, testUnit); } /** * Index the given {@link CompilationUnit}. */ protected final void indexUnit(CompilationUnit unit) { AnalysisContext context = unit.getElement().getContext(); index.indexUnit(context, unit); } /** * Resolve and index the given source. */ protected final CompilationUnit indexUnit(Source source) throws Exception { CompilationUnit unit = parseUnit(source); indexUnit(unit); return unit; } /** * Parses and index given source code. */ protected final CompilationUnit indexUnit(String path, String code) throws Exception { CompilationUnit unit = parseUnit(path, code); indexUnit(unit); return unit; } /** * Prints lines of result applying {@link Refactoring} to the the {@link #testSource}. */ protected final void printRefactoringTestSourceResult(AnalysisContext context, Refactoring refactoring) throws Exception { Change refactoringChange = refactoring.createChange(pm); SourceChange testChange = getSourceChange(refactoringChange, testSource); String testResult = getChangeResult(context, testSource, testChange); printSourceLines(testResult); } @Override protected void setUp() throws Exception { super.setUp(); // run Index IndexStore indexStore = IndexFactory.newSplitIndexStore(new MemoryNodeManager()); index = IndexFactory.newIndex(indexStore); new Thread() { @Override public void run() { index.run(); } }.start(); searchEngine = SearchEngineFactory.createSearchEngine(index); // search for something, ensure that Index is running before we will try to stop it searchEngine.searchDeclarations("no-such-name", null, null); } @Override protected void tearDown() throws Exception { index.stop(); index = null; searchEngine = null; super.tearDown(); } }