// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.application.impl;

import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.util.Pair;
import com.intellij.testFramework.LightPlatformTestCase;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.concurrency.CancellablePromise;

/**
 * @author peter
 */
public class NonBlockingReadActionTest extends LightPlatformTestCase {

  public void testCoalesceEqual() throws Exception {
    CancellablePromise<String> promise = WriteAction.compute(() -> {
      CancellablePromise<String> promise1 =
        ReadAction.nonBlocking(() -> "y").coalesceBy("foo").submit(AppExecutorUtil.getAppExecutorService());
      assertFalse(promise1.isCancelled());

      CancellablePromise<String> promise2 =
        ReadAction.nonBlocking(() -> "x").coalesceBy("foo").submit(AppExecutorUtil.getAppExecutorService());
      assertTrue(promise1.isCancelled());
      assertFalse(promise2.isCancelled());
      return promise2;
    });
    String result = getResult(promise);
    assertEquals("x", result);
  }

  public void testDoNotCoalesceDifferent() throws Exception {
    Pair<CancellablePromise<String>, CancellablePromise<String>> promises = WriteAction.compute(
      () -> Pair.create(ReadAction.nonBlocking(() -> "x").coalesceBy("foo").submit(AppExecutorUtil.getAppExecutorService()),
                        ReadAction.nonBlocking(() -> "y").coalesceBy("bar").submit(AppExecutorUtil.getAppExecutorService())));
    assertEquals("x", getResult(promises.first));
    assertEquals("y", getResult(promises.second));
  }

  private static String getResult(CancellablePromise<String> promise) throws InterruptedException, java.util.concurrent.ExecutionException {
    while (!promise.isDone()) {
      UIUtil.dispatchAllInvocationEvents();
    }
    return promise.get();
  }
}

@@ -182,16 +182,71 @@
 .impl;%0A%0A
+import com.intellij.openapi.application.ModalityState;%0A
 import c
@@ -521,63 +521,295 @@
 til.
-ui.UIUtil;%0Aimport org.jetbrains.concurrency.Cancellable
+concurrency.Semaphore;%0Aimport com.intellij.util.concurrency.SequentialTaskExecutor;%0Aimport org.jetbrains.concurrency.CancellablePromise;%0A%0Aimport java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.TimeUnit;%0A%0Aimport static com.intellij.testFramework.PlatformTestUtil.waitFor
 Prom
@@ -944,33 +944,16 @@
 eEqual()
- throws Exception
  %7B%0A    C
@@ -1502,25 +1502,30 @@
 esult = 
-getResult
+waitForPromise
 (promise
@@ -1609,25 +1609,8 @@
 nt()
- throws Exception
  %7B%0A 
@@ -1979,25 +1979,30 @@
 ls(%22x%22, 
-getResult
+waitForPromise
 (promise
@@ -2034,25 +2034,30 @@
 ls(%22y%22, 
-getResult
+waitForPromise
 (promise
@@ -2080,251 +2080,578 @@
 %0A  p
-riva
+ublic void 
 te
- 
 st
-atic String getResult(CancellablePromise%3CString%3E promise) throws InterruptedException, java.util.concurrent.ExecutionException %7B%0A    while (!promise.isDone()) %7B%0A      UIUtil.dispatchAllInvocationEvents();%0A    %7D%0A    return promise.get(
+DoNotBlockExecutorThreadWhileWaitingForEdtFinish() throws Exception %7B%0A    Semaphore semaphore = new Semaphore(1);%0A    ExecutorService executor = SequentialTaskExecutor.createSequentialApplicationPoolExecutor(getName());%0A    CancellablePromise%3CVoid%3E promise = ReadAction%0A      .nonBlocking(() -%3E %7B%7D)%0A      .finishOnUiThread(ModalityState.defaultModalityState(), __ -%3E semaphore.up())%0A      .submit(executor);%0A    assertFalse(semaphore.isUp());%0A    executor.submit(() -%3E %7B%7D).get(10, TimeUnit.SECONDS); // shouldn't fail by timeout%0A    waitForPromise(promise
 );%0A 

add a test for NonBlockingReadActionImpl: release background thread while waiting for EDT