/* * Copyright (c) 2014, 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.server.internal; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.dart.server.AnalysisServerListener; import junit.framework.Assert; import junit.framework.AssertionFailedError; import org.dartlang.analysis.server.protocol.*; import java.util.List; import java.util.Map; import static org.fest.assertions.Assertions.assertThat; public class TestAnalysisServerListener implements AnalysisServerListener { private final Map<String, CompletionResult> completionsMap = Maps.newHashMap(); private final List<String> flushedResults = Lists.newArrayList(); private final Map<String, List<SearchResult>> searchResultsMap = Maps.newHashMap(); private final List<AnalysisServerError> serverErrors = Lists.newArrayList(); private final Map<String, List<AnalysisError>> sourcesErrors = Maps.newHashMap(); private final List<String> analyzedFiles = Lists.newArrayList(); private final Map<String, List<HighlightRegion>> highlightsMap = Maps.newHashMap(); private final Map<String, List<ImplementedClass>> implementedClassesMap = Maps.newHashMap(); private final Map<String, List<ImplementedMember>> implementedMembersMap = Maps.newHashMap(); private final Map<String, List<NavigationRegion>> navigationMap = Maps.newHashMap(); private final Map<String, List<Occurrences>> occurrencesMap = Maps.newHashMap(); private final Map<String, Outline> outlineMap = Maps.newHashMap(); private final Map<String, List<OverrideMember>> overridesMap = Maps.newHashMap(); private boolean serverConnected = false; private AnalysisStatus analysisStatus = null; public synchronized void assertAnalysisStatus(AnalysisStatus expectedStatus) { Assert.assertEquals(expectedStatus.isAnalyzing(), analysisStatus.isAnalyzing()); Assert.assertEquals(expectedStatus.getAnalysisTarget(), analysisStatus.getAnalysisTarget()); } /** * Assert that the passed set of analyzed files equals the last set passed to the server. * * @param files the list of expected analyzed file paths * @throws AssertionFailedError if a different set of strings is passed than was expected */ public synchronized void assertAnalyzedFiles(List<String> files) { assertThat(getAnalyzedFiles()).isEqualTo(files); } /** * Assert that the number of errors that have been gathered matches the number of errors that are * given and that they have the expected error codes. The order in which the errors were gathered * is ignored. * * @param file the file to check errors for * @param expectedErrorCodes the error codes of the errors that should have been gathered * @throws AssertionFailedError if a different number of errors have been gathered than were * expected */ public synchronized void assertErrorsWithAnalysisErrors(String file, AnalysisError... expectedErrors) { List<AnalysisError> errors = getErrors(file); assertErrorsWithAnalysisErrors(errors, expectedErrors); } /** * Asserts the list of flushed results. */ public synchronized void assertFlushedResults(List<String> expectedFlushedResults) { assertThat(expectedFlushedResults).isEqualTo(flushedResults); } /** * Asserts that there was no {@link AnalysisServerError} reported. */ public synchronized void assertNoServerErrors() { assertThat(serverErrors).isEmpty(); } public synchronized void assertServerConnected(boolean expectedConnected) { Assert.assertEquals(expectedConnected, serverConnected); } public void assertServerErrors(List<AnalysisServerError> expectedErrors) { Assert.assertEquals(expectedErrors.size(), serverErrors.size()); for (int i = 0; i < expectedErrors.size(); i++) { Assert.assertTrue(expectedErrors.get(i).equals(serverErrors.get(i))); } } /** * Removes all of reported {@link NavigationRegion}s. */ public synchronized void clearNavigationRegions() { navigationMap.clear(); } /** * Removes all of reported {@link Occurrences}s. */ public synchronized void clearOccurrences() { occurrencesMap.clear(); } /** * Removes all of reported {@link OverrideMember}. */ public synchronized void clearOverrides() { overridesMap.clear(); } @Override public void computedAnalyzedFiles(List<String> directories) { analyzedFiles.clear(); analyzedFiles.addAll(directories); } @Override public synchronized void computedCompletion(String completionId, int replacementOffset, int replacementLength, List<CompletionSuggestion> suggestions, boolean isLast) { // computed completion results are aggregate, replacing any prior results completionsMap.put(completionId, new CompletionResult(replacementOffset, replacementLength, suggestions, isLast)); } @Override public synchronized void computedErrors(String file, List<AnalysisError> errors) { sourcesErrors.put(file, errors); } @Override public synchronized void computedHighlights(String file, List<HighlightRegion> highlights) { highlightsMap.put(file, highlights); } @Override public void computedImplemented(String file, List<ImplementedClass> implementedClasses, List<ImplementedMember> implementedMembers) { implementedClassesMap.put(file, implementedClasses); implementedMembersMap.put(file, implementedMembers); } @Override public synchronized void computedLaunchData(String file, String kind, String[] referencedFiles) { // TODO(brianwilkerson) Add tests for this notification and implement this method appropriately } @Override public synchronized void computedNavigation(String file, List<NavigationRegion> targets) { navigationMap.put(file, targets); } @Override public void computedOccurrences(String file, List<Occurrences> occurrencesArray) { occurrencesMap.put(file, occurrencesArray); } @Override public synchronized void computedOutline(String file, Outline outline) { outlineMap.put(file, outline); } @Override public void computedOverrides(String file, List<OverrideMember> overrides) { overridesMap.put(file, overrides); } @Override public void computedSearchResults(String searchId, List<SearchResult> results, boolean last) { searchResultsMap.put(searchId, results); } /** * Returns a navigation {@link NavigationTarget} at the given position. */ public synchronized NavigationTarget findNavigationElement(String file, int offset) { List<NavigationRegion> regions = getNavigationRegions(file); if (regions != null) { for (NavigationRegion navigationRegion : regions) { if (navigationRegion.containsInclusive(offset)) { return navigationRegion.getTargetObjects().get(0); } } } return null; } @Override public synchronized void flushedResults(List<String> files) { flushedResults.addAll(files); } /** * Returns the last set of analyzed files sent from the server. */ public synchronized List<String> getAnalyzedFiles() { return analyzedFiles; } public boolean getCompletionIsLast(String completionId) { CompletionResult result = completionsMap.get(completionId); if (result == null) { throw new AssertionFailedError("Expected completion response: " + completionId); } return result.last; } public int getCompletionReplacementLength(String completionId) { CompletionResult result = completionsMap.get(completionId); if (result == null) { throw new AssertionFailedError("Expected completion response: " + completionId); } return result.replacementLength; } public int getCompletionReplacementOffset(String completionId) { CompletionResult result = completionsMap.get(completionId); if (result == null) { throw new AssertionFailedError("Expected completion response: " + completionId); } return result.replacementOffset; } /** * Returns list of {@link CompletionSuggestion} for the given completion id, maybe {@code null} if * have not been ever notified. */ public synchronized List<CompletionSuggestion> getCompletions(String completionId) { CompletionResult result = completionsMap.get(completionId); return result != null ? result.suggestions : null; } /** * Returns {@link AnalysisError} for the given file, may be empty, but not {@code null}. */ public synchronized List<AnalysisError> getErrors(String file) { List<AnalysisError> errors = sourcesErrors.get(file); if (errors == null) { return AnalysisError.EMPTY_LIST; } return errors; } /** * Returns {@link HighlightRegion}s for the given file, maybe {@code null} if have not been ever * notified. */ public synchronized List<HighlightRegion> getHighlightRegions(String file) { return highlightsMap.get(file); } /** * Returns {@link ImplementedClass}s for the given file, maybe {@code null} if have not been ever * notified. */ public synchronized List<ImplementedClass> getImplementedClasses(String file) { return implementedClassesMap.get(file); } /** * Returns {@link ImplementedMember}s for the given file, maybe {@code null} if have not been ever * notified. */ public synchronized List<ImplementedMember> getImplementedMembers(String file) { return implementedMembersMap.get(file); } /** * Returns {@link NavigationRegion}s for the given file, maybe {@code null} if have not been ever * notified. */ public synchronized List<NavigationRegion> getNavigationRegions(String file) { return navigationMap.get(file); } /** * Returns {@link Occurrences}s for the given file, maybe {@code null} if have not been ever * notified. */ public synchronized List<Occurrences> getOccurrences(String file) { return occurrencesMap.get(file); } /** * Returns {@link Outline} for the given {@link Source}, maybe {@code null} if have not been ever * notified. */ public synchronized Outline getOutline(String file) { return outlineMap.get(file); } /** * Returns {@link OverrideMember}s for the given file, maybe {@code null} if have not been ever * notified. */ public synchronized List<OverrideMember> getOverrides(String file) { return overridesMap.get(file); } /** * Returns {@link SearchResult[]} for the given search id, maybe {@code null} if have not been * ever notified. */ public List<SearchResult> getSearchResults(String searchId) { return searchResultsMap.get(searchId); } @Override public void requestError(RequestError requestError) { } @Override public synchronized void serverConnected(String version) { serverConnected = true; } @Override public synchronized void serverError(boolean isFatal, String message, String stackTrace) { serverErrors.add(new AnalysisServerError(isFatal, message, stackTrace)); } @Override public void serverIncompatibleVersion(String version) { } @Override public synchronized void serverStatus(AnalysisStatus analysisStatus, PubStatus pubStatus) { this.analysisStatus = analysisStatus; } /** * Assert that the array of actual {@link AnalysisError}s match the array of expected * {@link AnalysisError}s. * * @param actualErrors the actual set of errors that were created for some analysis * @param expectedErrors the expected array of errors */ private void assertErrorsWithAnalysisErrors(List<AnalysisError> actualErrors, AnalysisError[] expectedErrors) { if (actualErrors == null && expectedErrors == null) { return; } // assert that the arrays have the same length Assert.assertEquals(expectedErrors.length, actualErrors.size()); AnalysisError[] actualErrorsArray = actualErrors.toArray(new AnalysisError[actualErrors.size()]); // assert that the actualErrors contains all of the expected errors for (AnalysisError expectedError : expectedErrors) { // individual calls to assert each error are made for better messaging when there is a failure assertThat(actualErrorsArray).contains(expectedError); } } private final static class CompletionResult { final int replacementOffset; final int replacementLength; final List<CompletionSuggestion> suggestions; final boolean last; public CompletionResult(int replacementOffset, int replacementLength, List<CompletionSuggestion> suggestions, boolean last) { this.replacementOffset = replacementOffset; this.replacementLength = replacementLength; this.suggestions = suggestions; this.last = last; } } }