<commit_before>// Copyright 2000-2018 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.testGuiFramework.impl

import com.intellij.testGuiFramework.cellReader.ExtendedJTreeCellReader
import com.intellij.testGuiFramework.driver.ExtendedJTreePathFinder
import com.intellij.testGuiFramework.fixtures.ActionButtonFixture
import com.intellij.testGuiFramework.fixtures.GutterFixture
import com.intellij.testGuiFramework.fixtures.extended.ExtendedJTreePathFixture
import com.intellij.testGuiFramework.framework.Timeouts
import com.intellij.testGuiFramework.framework.toPrintable
import com.intellij.testGuiFramework.util.*
import org.fest.swing.exception.ComponentLookupException
import org.fest.swing.exception.LocationUnavailableException
import org.fest.swing.exception.WaitTimedOutError
import org.fest.swing.timing.Condition
import org.fest.swing.timing.Pause
import org.hamcrest.Matcher
import org.junit.After
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.rules.ErrorCollector
import org.junit.rules.TestName
import java.awt.IllegalComponentStateException

open class GuiTestCaseExt : GuiTestCase() {

  @Rule
  @JvmField
  val testMethod = TestName()

  @Rule
  @JvmField
  val screenshotsDuringTest = ScreenshotsDuringTest(1000) // = 1 sec

  @Rule
  @JvmField
  val logActionsDuringTest = LogActionsDuringTest()

  val projectFolder: String by lazy {
    projectsFolder.newFolder(testMethod.methodName).canonicalPath
  }

//  @Rule
//  @JvmField
//  val collector = object : ErrorCollector() {
//    override fun addError(error: Throwable?) {
//      val screenshotName = testName + "." + testMethod.methodName
//      takeScreenshotOnFailure(error, screenshotName)
//      super.addError(error)
//    }
//  }

  @Before
  open fun setUp() {
    logStartTest(testMethod.methodName)
  }

  @After
  fun tearDown() {
    logEndTest(testMethod.methodName)
  }

  open fun isIdeFrameRun(): Boolean = true
}

fun <T> ErrorCollector.checkThat(value: T, matcher: Matcher<T>, reason: () -> String) {
  checkThat(reason(), value, matcher)
}

/**
 * Closes the current project
 * */
fun GuiTestCase.closeProject() {
  ideFrame {
    logUIStep("Close the project")
    waitAMoment()
    closeProject()
  }
}

/**
 * Provide waiting for background tasks to finish
 * This function should be used instead of  [waitForBackgroundTasksToFinish]
 * because sometimes the latter doesn't wait enough time
 * */
fun GuiTestCase.waitAMoment(attempts: Int = 0) {
  val maxAttempts = 3
  ideFrame {
    this.waitForBackgroundTasksToFinish()
    val asyncIcon = indexingProcessIconNullable(Timeouts.noTimeout)
    if(asyncIcon != null){
      val timeoutForBackgroundTasks = Timeouts.minutes10
      try {
        asyncIcon.click()
        waitForPanelToDisappear(
          panelTitle = "Background Tasks",
          timeoutToAppear = Timeouts.seconds01,
          timeoutToDisappear = timeoutForBackgroundTasks
        )
      }
      catch (e: IllegalStateException){
        // asyncIcon searched earlier might disappear at all (it's ok)
        // or new one is shown. So let's try to search it again
        if(attempts < maxAttempts)
          waitAMoment(attempts + 1)
        else{
          if(indexingProcessIconNullable(Timeouts.noTimeout) !=null)
            throw WaitTimedOutError("Async icon is shown, but we cannot click on it after $maxAttempts attempts")
        }
      }
      catch (e: IllegalComponentStateException){
        // do nothing - asyncIcon disappears, background process has stopped
      }
      catch (e: ComponentLookupException){
        // do nothing - panel hasn't appeared and it seems ok
      }
      catch (e: WaitTimedOutError) {
        throw WaitTimedOutError("Background process hadn't finished after ${timeoutForBackgroundTasks.toPrintable()}")
      }
    }
  }
  robot().waitForIdle()
}

/**
 * Performs test whether the specified item exists in a tree
 * Note: the dialog with the investigated tree must be open
 * before using this test
 * @param expectedItem - expected exact item
 * @param name - name of item kind, such as "Library" or "Facet". Used for understandable error message
 * @param predicate - searcher rule, how to compare an item and name. By default they are compared by equality
 * */
fun GuiTestCase.testTreeItemExist(name: String, vararg expectedItem: String, predicate: FinderPredicate = Predicate.equality) {
  ideFrame {
    logInfo("Check that $name -> ${expectedItem.joinToString(" -> ")} exists in a tree element")
    kotlin.assert(exists { jTree(*expectedItem, predicate = predicate) }) { "$name '${expectedItem.joinToString(", ")}' not found" }
  }
}

/**
 * Performs test whether the specified item exists in a list
 * Note: the dialog with the investigated list must be open
 * before using this test<commit_msg>[gui-test] waitAMoment: another possible exception processed<commit_after>// Copyright 2000-2018 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.testGuiFramework.impl

import com.intellij.testGuiFramework.cellReader.ExtendedJTreeCellReader
import com.intellij.testGuiFramework.driver.ExtendedJTreePathFinder
import com.intellij.testGuiFramework.fixtures.ActionButtonFixture
import com.intellij.testGuiFramework.fixtures.GutterFixture
import com.intellij.testGuiFramework.fixtures.extended.ExtendedJTreePathFixture
import com.intellij.testGuiFramework.framework.Timeouts
import com.intellij.testGuiFramework.framework.toPrintable
import com.intellij.testGuiFramework.util.*
import org.fest.swing.exception.ComponentLookupException
import org.fest.swing.exception.LocationUnavailableException
import org.fest.swing.exception.WaitTimedOutError
import org.fest.swing.timing.Condition
import org.fest.swing.timing.Pause
import org.hamcrest.Matcher
import org.junit.After
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.rules.ErrorCollector
import org.junit.rules.TestName
import java.awt.IllegalComponentStateException

open class GuiTestCaseExt : GuiTestCase() {

  @Rule
  @JvmField
  val testMethod = TestName()

  @Rule
  @JvmField
  val screenshotsDuringTest = ScreenshotsDuringTest(1000) // = 1 sec

  @Rule
  @JvmField
  val logActionsDuringTest = LogActionsDuringTest()

  val projectFolder: String by lazy {
    projectsFolder.newFolder(testMethod.methodName).canonicalPath
  }

//  @Rule
//  @JvmField
//  val collector = object : ErrorCollector() {
//    override fun addError(error: Throwable?) {
//      val screenshotName = testName + "." + testMethod.methodName
//      takeScreenshotOnFailure(error, screenshotName)
//      super.addError(error)
//    }
//  }

  @Before
  open fun setUp() {
    logStartTest(testMethod.methodName)
  }

  @After
  fun tearDown() {
    logEndTest(testMethod.methodName)
  }

  open fun isIdeFrameRun(): Boolean = true
}

fun <T> ErrorCollector.checkThat(value: T, matcher: Matcher<T>, reason: () -> String) {
  checkThat(reason(), value, matcher)
}

/**
 * Closes the current project
 * */
fun GuiTestCase.closeProject() {
  ideFrame {
    logUIStep("Close the project")
    waitAMoment()
    closeProject()
  }
}

/**
 * Provide waiting for background tasks to finish
 * This function should be used instead of  [waitForBackgroundTasksToFinish]
 * because sometimes the latter doesn't wait enough time
 * */
fun GuiTestCase.waitAMoment(attempts: Int = 0) {
  val maxAttempts = 3
  ideFrame {
    this.waitForBackgroundTasksToFinish()
    val asyncIcon = indexingProcessIconNullable(Timeouts.noTimeout)
    if(asyncIcon != null){
      val timeoutForBackgroundTasks = Timeouts.minutes10
      try {
        asyncIcon.click()
        waitForPanelToDisappear(
          panelTitle = "Background Tasks",
          timeoutToAppear = Timeouts.seconds01,
          timeoutToDisappear = timeoutForBackgroundTasks
        )
      }
      catch (ignore: NullPointerException) {
        // if asyncIcon disappears at once after getting the NPE from fest might occur
        // but it's ok - nothing to wait anymore
      }
      catch (ignore: IllegalComponentStateException){
        // do nothing - asyncIcon disappears, background process has stopped
      }
      catch (ignore: ComponentLookupException){
        // do nothing - panel hasn't appeared and it seems ok
      }
      catch (e: IllegalStateException){
        // asyncIcon searched earlier might disappear at all (it's ok)
        // or new one is shown. So let's try to search it again
        if(attempts < maxAttempts)
          waitAMoment(attempts + 1)
        else{
          if(indexingProcessIconNullable(Timeouts.noTimeout) !=null)
            throw WaitTimedOutError("Async icon is shown, but we cannot click on it after $maxAttempts attempts")
        }
      }
      catch (e: WaitTimedOutError) {
        throw WaitTimedOutError("Background process hadn't finished after ${timeoutForBackgroundTasks.toPrintable()}")
      }
    }
  }
  robot().waitForIdle()
}

/**
 * Performs test whether the specified item exists in a tree
 * Note: the dialog with the investigated tree must be open
 * before using this test
 * @param expectedItem - expected exact item
 * @param name - name of item kind, such as "Library" or "Facet". Used for understandable error message
 * @param predicate - searcher rule, how to compare an item and name. By default they are compared by equality
 * */
fun GuiTestCase.testTreeItemExist(name: String, vararg expectedItem: String, predicate: FinderPredicate = Predicate.equality) {
  ideFrame {
    logInfo("Check that $name -> ${expectedItem.joinToString(" -> ")} exists in a tree element")
    kotlin.assert(exists { jTree(*expectedItem, predicate = predicate) }) { "$name '${expectedItem.joinToString(", ")}' not found" }
  }
}

/**
 * Performs test whether the specified item exists in a list
 * Note: the dialog with the investigated list must be open
 * before using this test
{'fraction_non_alphanumeric': 0.08999801547926176, 'fraction_numerical': 0.004365945624131772, 'mean_word_length': 3.7274859287054407, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '143411', 'n_tokens_mistral': 2967, 'n_tokens_neox': 2846, 'n_words': 815}