Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Unified Diff: editor/tools/plugins/com.google.dart.tools.ui_test/src/com/google/dart/tools/ui/internal/text/dart/DartReconcilingStrategyTest.java

Issue 22781002: Version 0.6.17.1 (Closed) Base URL: http://dart.googlecode.com/svn/trunk/dart/
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: editor/tools/plugins/com.google.dart.tools.ui_test/src/com/google/dart/tools/ui/internal/text/dart/DartReconcilingStrategyTest.java
===================================================================
--- editor/tools/plugins/com.google.dart.tools.ui_test/src/com/google/dart/tools/ui/internal/text/dart/DartReconcilingStrategyTest.java (revision 25990)
+++ editor/tools/plugins/com.google.dart.tools.ui_test/src/com/google/dart/tools/ui/internal/text/dart/DartReconcilingStrategyTest.java (working copy)
@@ -16,21 +16,24 @@
import com.google.common.base.Joiner;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.context.AnalysisContext;
-import com.google.dart.engine.context.AnalysisErrorInfo;
-import com.google.dart.engine.context.AnalysisException;
import com.google.dart.engine.context.ChangeNotice;
-import com.google.dart.engine.error.AnalysisError;
import com.google.dart.engine.internal.context.AnalysisContextImpl;
import com.google.dart.engine.sdk.DartSdk;
import com.google.dart.engine.sdk.DirectoryBasedDartSdk;
+import com.google.dart.engine.source.ContentCache;
import com.google.dart.engine.source.DartUriResolver;
import com.google.dart.engine.source.FileUriResolver;
import com.google.dart.engine.source.Source;
import com.google.dart.engine.source.SourceFactory;
import com.google.dart.engine.source.TestSource;
-import com.google.dart.engine.utilities.source.LineInfo;
+import com.google.dart.tools.core.analysis.model.AnalysisEvent;
+import com.google.dart.tools.core.analysis.model.AnalysisListener;
import com.google.dart.tools.core.analysis.model.Project;
+import com.google.dart.tools.core.analysis.model.ResolvedEvent;
+import com.google.dart.tools.core.internal.builder.AnalysisWorker;
+import static com.google.dart.engine.utilities.io.FileUtilities2.createFile;
+
import junit.framework.TestCase;
import org.eclipse.jface.text.Document;
@@ -39,181 +42,194 @@
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusListener;
-import java.util.ArrayList;
+import java.io.File;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
public class DartReconcilingStrategyTest extends TestCase {
- private final class MockContext extends com.google.dart.tools.core.internal.builder.MockContext {
- private final Object lock = new Object();
- private String cachedContents = null;
- private Exception exception = null;
- private CompilationUnit unit = null;
- private boolean resolved = false;
- private AnalysisErrorInfo unitInfo;
- private List<Source> priorityOrder = new ArrayList<Source>();
+ /**
+ * Content cache that can wait for contents to be set.
+ *
+ * @see #expectSetContentsFor(Source)
+ * @see #waitForSetContents(Source, long)
+ */
+ private class MockCache extends ContentCache {
+ private Source expectedSource = null;
+ private CountDownLatch expectedLatch = null;
- public Exception getException() {
- return exception;
+ public void expectSetContentsFor(Source source) {
+ expectedSource = source;
+ expectedLatch = new CountDownLatch(1);
}
@Override
- public Source[] getLibrariesContaining(Source source) {
- if (mockSource.equals(source)) {
- return new Source[] {mockSource};
+ public boolean setContents(Source source, String contents) {
+ boolean result = super.setContents(source, contents);
+ if (source == expectedSource) {
+ expectedLatch.countDown();
}
- return super.getLibrariesContaining(source);
+ return result;
}
- public CompilationUnit getUnit() {
- return unit;
+ public String waitForSetContents(Source source, long milliseconds) {
+ if (source != expectedSource) {
+ throw new IllegalArgumentException("Should call expectSetContentsFor");
+ }
+ try {
+ assertTrue(expectedLatch.await(milliseconds, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ assertEquals(0, expectedLatch.getCount());
+ }
+ expectedSource = null;
+ expectedLatch = null;
+ return getContents(source);
}
+ }
- @Override
- public CompilationUnit parseCompilationUnit(Source source) throws AnalysisException {
- assertSame(mockSource, source);
- synchronized (lock) {
- if (unit != null) {
- final AnalysisContextImpl context = new AnalysisContextImpl();
- context.setContents(mockSource, cachedContents);
- unit = context.parseCompilationUnit(mockSource);
- unitInfo = context.getErrors(mockSource);
+ /**
+ * Analysis context that can wait for priority order and resolution.
+ */
+ private class MockContext extends AnalysisContextImpl {
+ private CountDownLatch priorityOrderLatch = null;
+ private List<Source> priorityOrder = null;
+ private long performAnalysisTaskTime = 0;
+ private long setPriorityOrderTime = 0;
+ private CountDownLatch resolvedLatch = null;
+ private Source resolvedSource = null;
+ private CompilationUnit resolvedUnit = null;
+ private int flushCount = 0;
+
+ private final AnalysisListener backgroundAnalysisListener = new AnalysisListener() {
+ @Override
+ public void complete(AnalysisEvent event) {
+ synchronized (this) {
+ if (resolvedLatch != null && resolvedLatch.getCount() > 0) {
+ if (event.getContext() == MockContext.this) {
+ resolvedUnit = getResolvedCompilationUnit(resolvedSource, resolvedSource);
+ resolvedLatch.countDown();
+ }
+ }
}
- return unit;
}
- }
- @Override
- public ChangeNotice[] performAnalysisTask() {
- if (!resolved) {
- resolved = true;
- final CompilationUnit resolvedUnit;
- final AnalysisErrorInfo resolvedInfo;
- synchronized (lock) {
- try {
- resolvedUnit = parseCompilationUnit(mockSource);
- resolvedInfo = unitInfo;
- } catch (AnalysisException e) {
- exception = e;
- return super.performAnalysisTask();
+ @Override
+ public void resolved(ResolvedEvent event) {
+ synchronized (this) {
+ if (resolvedLatch != null && resolvedLatch.getCount() > 0) {
+ if (event.getContext() == MockContext.this && event.getSource() == resolvedSource) {
+ resolvedUnit = event.getUnit();
+ resolvedLatch.countDown();
+ }
}
}
- return new ChangeNotice[] {new ChangeNotice() {
+ }
+ };
- @Override
- public CompilationUnit getCompilationUnit() {
- return resolvedUnit;
- }
+ public void assertPrioritySetBeforeBackgroundAnalysis() {
+ assertTrue(setPriorityOrderTime > 0);
+ assertTrue(setPriorityOrderTime < performAnalysisTaskTime || performAnalysisTaskTime == 0);
+ }
- @Override
- public AnalysisError[] getErrors() {
- if (resolvedInfo != null) {
- return resolvedInfo.getErrors();
- }
- return null;
- }
+ public void expectResolved(Source source) {
+ synchronized (backgroundAnalysisListener) {
+ resolvedSource = source;
+ resolvedLatch = new CountDownLatch(1);
+ resolvedUnit = null;
+ AnalysisWorker.addListener(backgroundAnalysisListener);
+ }
+ }
- @Override
- public LineInfo getLineInfo() {
- return resolvedInfo.getLineInfo();
- }
+ public void expectSetPriorityOrder() {
+ priorityOrderLatch = new CountDownLatch(1);
+ }
- @Override
- public Source getSource() {
- return mockSource;
- }
- }};
+ /**
+ * Flush the resolved compilation unit for the specified source by creating and resolving other
+ * sources.
+ *
+ * @param source the source of the compilation unit to be flushed (not <code>null</code>)
+ */
+ public void flushCompilationUnit(Source source) throws Exception {
+ for (int i = 0; i < 128; i++) {
+ File newFile = createFile("/test_" + ++flushCount + ".dart");
+ Source newSource = new TestSource(mockCache, newFile, INITIAL_CONTENTS);
+ assertNotNull(resolveCompilationUnit(newSource, newSource));
}
- return super.performAnalysisTask();
}
+ public List<Source> getPriorityOrder() {
+ return priorityOrder;
+ }
+
@Override
- public void setAnalysisPriorityOrder(List<Source> sources) {
- synchronized (lock) {
- priorityOrder = sources;
- lock.notifyAll();
+ public ChangeNotice[] performAnalysisTask() {
+ if (performAnalysisTaskTime == 0) {
+ performAnalysisTaskTime = System.currentTimeMillis();
+ if (performAnalysisTaskTime == setPriorityOrderTime) {
+ performAnalysisTaskTime++;
+ }
}
+ return super.performAnalysisTask();
}
@Override
- public void setContents(Source source, String contents) {
- assertSame(mockSource, source);
- synchronized (lock) {
- cachedContents = contents;
- resolved = false;
- unit = null;
- unitInfo = null;
- lock.notifyAll();
+ public void setAnalysisPriorityOrder(List<Source> sources) {
+ super.setAnalysisPriorityOrder(sources);
+ if (setPriorityOrderTime == 0) {
+ setPriorityOrderTime = System.currentTimeMillis();
+ if (setPriorityOrderTime == performAnalysisTaskTime) {
+ setPriorityOrderTime++;
+ }
}
+ if (priorityOrderLatch != null) {
+ priorityOrder = sources;
+ priorityOrderLatch.countDown();
+ }
}
- /**
- * Wait up to the specified number of milliseconds for the cached contents.
- *
- * @param milliseconds the maximum number of milliseconds to wait
- * @param expectedContents the expected cached contents
- * @return <code>true</code> if the contents match the expected contents
- */
- public boolean waitFoCachedContents(long milliseconds, String expectedContents) {
- synchronized (lock) {
- long end = System.currentTimeMillis() + milliseconds;
- while (true) {
- if (expectedContents == null ? cachedContents == null
- : expectedContents.equals(cachedContents)) {
- return true;
- }
- long delta = end - System.currentTimeMillis();
- if (delta <= 0) {
- return false;
- }
- try {
- lock.wait(delta);
- } catch (InterruptedException e) {
- //$FALL-THROUGH$
- }
- }
+ public CompilationUnit waitForResolution(Source source, long milliseconds) {
+ if (source != resolvedSource) {
+ throw new IllegalArgumentException("Call expectResolved");
}
+ try {
+ assertTrue(resolvedLatch.await(milliseconds, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ assertEquals(0, resolvedLatch.getCount());
+ }
+ synchronized (backgroundAnalysisListener) {
+ AnalysisWorker.removeListener(backgroundAnalysisListener);
+ resolvedLatch = null;
+ resolvedSource = null;
+ return resolvedUnit;
+ }
}
- /**
- * Wait up to the specified number of milliseconds for the priority order to be set.
- *
- * @param expectedContents the expected cached contents
- * @param milliseconds the maximum number of milliseconds to wait
- * @return <code>true</code> if the contents match the expected contents
- */
- public boolean waitForAnalysisPriorityOrder(long milliseconds, Source... expectedOrder) {
- synchronized (lock) {
- long end = System.currentTimeMillis() + milliseconds;
- while (true) {
- if (Arrays.asList(expectedOrder).equals(priorityOrder)) {
- return true;
- }
- long delta = end - System.currentTimeMillis();
- if (delta <= 0) {
- return false;
- }
- try {
- lock.wait(delta);
- } catch (InterruptedException e) {
- //$FALL-THROUGH$
- }
- }
+ public List<Source> waitForSetPriorityOrder(long milliseconds) {
+ if (priorityOrderLatch == null) {
+ throw new IllegalStateException("Call expectSetPriorityOrder");
}
+ try {
+ assertTrue(priorityOrderLatch.await(milliseconds, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ assertEquals(0, priorityOrderLatch.getCount());
+ }
+ priorityOrderLatch = null;
+ return priorityOrder;
}
}
+ /**
+ * Mock editor for testing {@link DartReconcilingStrategy}
+ */
private final class MockEditor implements DartReconcilingEditor {
- private final Object lock = new Object();
-
+ private CountDownLatch appliedLatch = null;
+ private CompilationUnit appliedUnit = null;
private DisposeListener disposeListener = null;
-
private FocusListener focusListener = null;
- private CompilationUnit appliedUnit = null;
- private boolean applyCalled;
-
@Override
public void addViewerDisposeListener(DisposeListener listener) {
if (disposeListener != null) {
@@ -232,31 +248,21 @@
@Override
public void applyCompilationUnitElement(CompilationUnit unit) {
- synchronized (lock) {
- appliedUnit = unit;
- applyCalled = true;
- lock.notifyAll();
+ appliedUnit = unit;
+ if (appliedLatch != null) {
+ appliedLatch.countDown();
}
}
- public void clearApplyCalled() {
- applyCalled = true;
+ public void expectApply() {
+ appliedLatch = new CountDownLatch(1);
+ appliedUnit = null;
}
- public CompilationUnit getAppliedUnit() {
- synchronized (lock) {
- return appliedUnit;
- }
- }
-
public DisposeListener getDisposeListener() {
return disposeListener;
}
- public FocusListener getFocusListener() {
- return focusListener;
- }
-
@Override
public AnalysisContext getInputAnalysisContext() {
return mockContext;
@@ -278,29 +284,17 @@
return mockSource.getShortName();
}
- /**
- * Wait up to the specified amount of time for the
- * {@link #applyCompilationUnitElement(CompilationUnit)} method to be called.
- *
- * @param milliseconds the maximum number of milliseconds to wait
- * @return {@code true} if the method was called, else {@code false}
- */
- public boolean waitForApply(long milliseconds) {
- long end = System.currentTimeMillis() + milliseconds;
- synchronized (lock) {
- while (!applyCalled) {
- long delta = end - System.currentTimeMillis();
- if (delta <= 0) {
- return false;
- }
- try {
- lock.wait(delta);
- } catch (InterruptedException e) {
- //$FALL-THROUGH$
- }
- }
+ public CompilationUnit waitForApply(long milliseconds, boolean expectAnother) {
+ if (appliedLatch == null) {
+ throw new IllegalStateException("Call expectApply");
}
- return true;
+ try {
+ assertTrue(appliedLatch.await(milliseconds, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ assertEquals(0, appliedLatch.getCount());
+ }
+ appliedLatch = expectAnother ? new CountDownLatch(1) : null;
+ return appliedUnit;
}
}
@@ -310,87 +304,191 @@
"class A { foo() => 'two'; }");
MockEditor mockEditor = new MockEditor();
-
- Source mockSource = new TestSource(INITIAL_CONTENTS);
+ MockCache mockCache = new MockCache();
+ Source mockSource = new TestSource(mockCache, createFile("/test.dart"), INITIAL_CONTENTS);
MockContext mockContext = new MockContext();
- Document mockDocument = new Document();
+ Document mockDocument = new Document(INITIAL_CONTENTS);
DartReconcilingStrategy strategy = new DartReconcilingStrategy(mockEditor);
+ /**
+ * Assert reconciler clears cached contents when disposed
+ */
public void test_dispose() throws Exception {
mockContext.setContents(mockSource, INITIAL_CONTENTS);
mockContext.setAnalysisPriorityOrder(Arrays.asList(new Source[] {mockSource}));
+ mockCache.expectSetContentsFor(mockSource);
+ mockContext.expectSetPriorityOrder();
+
mockEditor.getDisposeListener().widgetDisposed(null);
- // assert reconciler clears cached contents when disposed
- assertTrue(mockContext.waitFoCachedContents(5000, null));
- assertTrue(mockContext.waitForAnalysisPriorityOrder(5000));
+
+ assertEquals(0, mockContext.waitForSetPriorityOrder(5000).size());
+ assertNull(mockCache.waitForSetContents(mockSource, 5000));
}
+ /**
+ * Assert unit resolved, applied, and order set during initialReconcile
+ */
public void test_initialReconcile() {
+ mockEditor.expectApply();
+ mockContext.expectResolved(mockSource);
+ mockContext.expectSetPriorityOrder();
+
strategy.initialReconcile();
- assertTrue(mockEditor.waitForApply(5000));
- assertSame(mockContext.getUnit(), mockEditor.getAppliedUnit());
- assertTrue(mockContext.waitForAnalysisPriorityOrder(5000, mockSource));
+
+ assertNotNull(mockEditor.waitForApply(5000, true));
+ CompilationUnit unit = mockContext.waitForResolution(mockSource, 5000);
+ assertNotNull(unit);
+ assertSame(unit, mockEditor.waitForApply(5000, false));
+ List<Source> priorityOrder = mockContext.waitForSetPriorityOrder(5000);
+ assertEquals(1, priorityOrder.size());
+ assertSame(mockSource, priorityOrder.get(0));
+ mockContext.assertPrioritySetBeforeBackgroundAnalysis();
}
+ /**
+ * Assert unit resolved, applied, and order set during initialReconcile after AST has been removed
+ * from the cache
+ */
+ public void test_initialReconcile_afterFlush() throws Exception {
+ assertNotNull(mockContext.resolveCompilationUnit(mockSource, mockSource));
+ mockContext.flushCompilationUnit(mockSource);
+ assertNull(mockContext.getResolvedCompilationUnit(mockSource, mockSource));
+
+ mockEditor.expectApply();
+ mockContext.expectResolved(mockSource);
+ mockContext.expectSetPriorityOrder();
+
+ strategy.initialReconcile();
+
+ assertNotNull(mockEditor.waitForApply(5000, true));
+ CompilationUnit unit = mockContext.waitForResolution(mockSource, 5000);
+ assertNotNull(unit);
+ assertSame(unit, mockEditor.waitForApply(5000, false));
+ List<Source> priorityOrder = mockContext.waitForSetPriorityOrder(5000);
+ assertEquals(1, priorityOrder.size());
+ assertSame(mockSource, priorityOrder.get(0));
+ mockContext.assertPrioritySetBeforeBackgroundAnalysis();
+ }
+
+ /**
+ * Assert unit resolved, applied, and order set during initialReconcile
+ */
+ public void test_initialReconcile_alreadyCached() throws Exception {
+ CompilationUnit unit = mockContext.resolveCompilationUnit(mockSource, mockSource);
+ assertNotNull(unit);
+ mockEditor.expectApply();
+ mockContext.expectResolved(mockSource);
+ mockContext.expectSetPriorityOrder();
+
+ strategy.initialReconcile();
+
+ assertSame(unit, mockEditor.waitForApply(5000, false));
+ List<Source> priorityOrder = mockContext.waitForSetPriorityOrder(5000);
+ assertEquals(1, priorityOrder.size());
+ assertSame(mockSource, priorityOrder.get(0));
+ mockContext.assertPrioritySetBeforeBackgroundAnalysis();
+ }
+
+ /**
+ * Assert editor with no context does not throw exception
+ */
public void test_initialReconcile_nullContext() {
mockContext = null;
+ assertNull(mockEditor.getInputAnalysisContext());
+
strategy.initialReconcile();
- assertNull(mockEditor.getAppliedUnit());
+
+ // test infrastructure asserts no exceptions
}
- // assert reconciler lazily sets cached contents and performs resolution
+ /**
+ * Assert reconciler lazily sets cached contents and performs resolution
+ */
public void test_initialState() throws Exception {
- assertTrue(mockContext.waitFoCachedContents(5000, null));
- assertNull(mockContext.getUnit());
- assertTrue(mockContext.waitForAnalysisPriorityOrder(5000));
+ assertNull(mockCache.getContents(mockSource));
+ assertNull(mockContext.getResolvedCompilationUnit(mockSource, mockSource));
+ assertNull(mockContext.getPriorityOrder());
}
- public void test_reconcileDirtyRegionIRegion() {
+ /**
+ * Assert that a document change clears the cached unit and a resolve resets it
+ */
+ public void test_reconcileDirtyRegionIRegion() throws Exception {
+ String newText = "//comment\n";
+
+ mockEditor.expectApply();
strategy.initialReconcile();
- assertTrue(mockEditor.waitForApply(5000));
- mockEditor.clearApplyCalled();
- strategy.reconcile(new DirtyRegion(0, 5, "ignored", "hello"), new Region(0, 5));
- assertTrue(mockEditor.waitForApply(5000));
- assertSame(mockContext.getUnit(), mockEditor.getAppliedUnit());
+ assertNotNull(mockEditor.waitForApply(5000, false));
+
+ mockEditor.expectApply();
+ mockDocument.replace(0, 0, newText);
+ assertNull(mockEditor.waitForApply(5000, false));
+
+ mockEditor.expectApply();
+ strategy.reconcile(new DirtyRegion(0, 0, DirtyRegion.INSERT, newText), new Region(0, 0));
+ CompilationUnit unit = mockEditor.waitForApply(5000, false);
+ assertNotNull(unit);
}
- public void test_reconcileDirtyRegionIRegion_nullContext() {
+ /**
+ * Assert editor with no context does not throw exception
+ */
+ public void test_reconcileDirtyRegionIRegion_nullContext() throws Exception {
+ String newText = "//comment\n";
+
mockContext = null;
strategy.initialReconcile();
- strategy.reconcile(new DirtyRegion(0, 5, "ignored", "hello"), new Region(0, 5));
- assertNull(mockEditor.getAppliedUnit());
+ mockDocument.replace(0, 0, newText);
+ strategy.reconcile(new DirtyRegion(0, 0, DirtyRegion.INSERT, newText), new Region(0, 0));
+
+ // test infrastructure asserts no exceptions
}
- public void test_reconcileIRegion() {
+ public void test_reconcileIRegion() throws Exception {
+ String newText = "//comment\n";
+
+ mockEditor.expectApply();
strategy.initialReconcile();
- assertTrue(mockEditor.waitForApply(5000));
- mockEditor.clearApplyCalled();
- strategy.reconcile(new Region(0, 5));
- assertTrue(mockEditor.waitForApply(5000));
- assertSame(mockContext.getUnit(), mockEditor.getAppliedUnit());
+ assertNotNull(mockEditor.waitForApply(5000, false));
+
+ mockEditor.expectApply();
+ mockDocument.replace(0, 0, newText);
+ assertNull(mockEditor.waitForApply(5000, false));
+
+ mockEditor.expectApply();
+ strategy.reconcile(new Region(0, newText.length()));
+ CompilationUnit unit = mockEditor.waitForApply(5000, false);
+ assertNotNull(unit);
}
- public void test_reconcileIRegion_nullContext() {
+ /**
+ * Assert editor with no context does not throw exception
+ */
+ public void test_reconcileIRegion_nullContext() throws Exception {
+ String newText = "//comment\n";
+
mockContext = null;
strategy.initialReconcile();
- strategy.reconcile(new Region(0, 5));
- assertNull(mockEditor.getAppliedUnit());
+ mockDocument.replace(0, 0, newText);
+ strategy.reconcile(new Region(0, newText.length()));
+
+ // test infrastructure asserts no exceptions
}
@Override
protected void setUp() throws Exception {
- super.setUp();
DartSdk sdk = DirectoryBasedDartSdk.getDefaultSdk();
- SourceFactory sourceFactory = new SourceFactory(new DartUriResolver(sdk), new FileUriResolver());
+ assertNotNull(sdk);
+ SourceFactory sourceFactory = new SourceFactory(
+ mockCache,
+ new DartUriResolver(sdk),
+ new FileUriResolver());
mockContext.setSourceFactory(sourceFactory);
strategy.setDocument(mockDocument);
}
@Override
protected void tearDown() throws Exception {
- if (mockContext != null) {
- assertNull(mockContext.getException());
- }
// Ensure that strategy removes its AnalysisWorker listener
if (strategy != null) {
strategy.dispose();

Powered by Google App Engine
This is Rietveld 408576698