mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[recent files + diff] IJ-MR-209657 IJPL-242683 Add test for diff files in recent files list
(cherry picked from commit 48d6b1b7eb89233d099bd68eef1e41c354801b88) GitOrigin-RevId: 0d0f2e8ae62cdace270414cfe8c0339ecebfa690
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a3e9476e35
commit
1620fd53ef
Generated
+1
@@ -1614,6 +1614,7 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/recentFiles/backend/intellij.platform.recentFiles.backend.iml" filepath="$PROJECT_DIR$/platform/recentFiles/backend/intellij.platform.recentFiles.backend.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/recentFiles/frontend/intellij.platform.recentFiles.frontend.iml" filepath="$PROJECT_DIR$/platform/recentFiles/frontend/intellij.platform.recentFiles.frontend.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/recentFiles/plugin/intellij.platform.recentFiles.plugin.iml" filepath="$PROJECT_DIR$/platform/recentFiles/plugin/intellij.platform.recentFiles.plugin.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/recentFiles/tests/intellij.platform.recentFiles.tests.iml" filepath="$PROJECT_DIR$/platform/recentFiles/tests/intellij.platform.recentFiles.tests.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/refactoring/intellij.platform.refactoring.iml" filepath="$PROJECT_DIR$/platform/refactoring/intellij.platform.refactoring.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/remote-core/intellij.platform.remote.core.iml" filepath="$PROJECT_DIR$/platform/remote-core/intellij.platform.remote.core.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/remote-servers/api/intellij.platform.remoteServers.iml" filepath="$PROJECT_DIR$/platform/remote-servers/api/intellij.platform.remoteServers.iml" />
|
||||
|
||||
@@ -628,6 +628,8 @@ jvm_library(
|
||||
"//xml/dom-tests:dom-tests_test_lib",
|
||||
"//plugins/IntelliLang/tests",
|
||||
"//plugins/IntelliLang/tests:tests_test_lib",
|
||||
"//platform/recentFiles/tests",
|
||||
"//platform/recentFiles/tests:tests_test_lib",
|
||||
"//xml/tests",
|
||||
"//xml/tests:tests_test_lib",
|
||||
"//jps/model-serialization:model-serialization-tests",
|
||||
|
||||
@@ -819,6 +819,7 @@ platform/recentFiles/backend
|
||||
platform/recentFiles/frontend
|
||||
platform/recentFiles/plugin
|
||||
platform/recentFiles/shared
|
||||
platform/recentFiles/tests
|
||||
platform/refactoring
|
||||
platform/remote-core
|
||||
platform/remote-driver/client
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<orderEntry type="module" module-name="intellij.tasks.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.xml.dom.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.langInjection.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.recentFiles.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.xml.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jps.model.serialization.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.java.guiForms.jps" scope="TEST" />
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
load("@community//build:tests-options.bzl", "jps_test")
|
||||
load("@rules_jvm//:jvm.bzl", "jvm_library")
|
||||
|
||||
### auto-generated section `build intellij.platform.recentFiles.tests` start
|
||||
|
||||
jvm_library(
|
||||
name = "tests",
|
||||
srcs = glob(
|
||||
[],
|
||||
allow_empty = True,
|
||||
),
|
||||
module_name = "intellij.platform.recentFiles.tests",
|
||||
visibility = ["//visibility:public"],
|
||||
runtime_deps = [
|
||||
# do not sort,
|
||||
"@lib//:kotlin-stdlib",
|
||||
"//platform/recentFiles/plugin",
|
||||
],
|
||||
)
|
||||
|
||||
jvm_library(
|
||||
name = "tests_test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(
|
||||
[
|
||||
"testSrc/**/*.kt",
|
||||
"testSrc/**/*.java",
|
||||
"testSrc/**/*.form",
|
||||
],
|
||||
allow_empty = True,
|
||||
),
|
||||
associates = [
|
||||
"//platform/recentFiles/backend",
|
||||
"//platform/recentFiles/backend:backend_test_lib",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
runtime_deps = [
|
||||
# do not sort,
|
||||
":tests",
|
||||
"//platform/recentFiles/plugin:plugin_test_lib",
|
||||
"//platform/platform-impl:ide-impl_test_lib",
|
||||
"//platform/platform-impl/rpc:rpc_test_lib",
|
||||
],
|
||||
deps = [
|
||||
# do not sort,
|
||||
"@lib//:kotlin-stdlib",
|
||||
"//platform/recentFiles/frontend",
|
||||
"//platform/recentFiles/frontend:frontend_test_lib",
|
||||
"//platform/recentFiles/shared:recentFiles",
|
||||
"//platform/recentFiles/shared:recentFiles_test_lib",
|
||||
"//platform/testFramework/junit5",
|
||||
"//platform/testFramework/junit5:junit5_test_lib",
|
||||
"//platform/testFramework",
|
||||
"//platform/testFramework:testFramework_test_lib",
|
||||
"//libraries/junit5",
|
||||
"//libraries/junit5:junit5_test_lib",
|
||||
"//libraries/kotlinx/coroutines/core",
|
||||
"//libraries/kotlinx/coroutines/core:core_test_lib",
|
||||
"//platform/core-api:core",
|
||||
"//platform/core-api:core_test_lib",
|
||||
"//platform/util/concurrency",
|
||||
"//platform/util/concurrency:concurrency_test_lib",
|
||||
"//platform/platform-impl:ide-impl",
|
||||
"//platform/platform-impl/rpc",
|
||||
"//platform/kernel/rpc.backend",
|
||||
"//platform/kernel/rpc.backend:rpc.backend_test_lib",
|
||||
"//platform/util:util-ui",
|
||||
"//platform/util:util-ui_test_lib",
|
||||
],
|
||||
)
|
||||
### auto-generated section `build intellij.platform.recentFiles.tests` end
|
||||
|
||||
### auto-generated section `iml intellij.platform.recentFiles.tests` start
|
||||
exports_files(
|
||||
[
|
||||
"intellij.platform.recentFiles.tests.iml",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
### auto-generated section `iml intellij.platform.recentFiles.tests` end
|
||||
|
||||
### auto-generated section `test intellij.platform.recentFiles.tests` start
|
||||
|
||||
jps_test(
|
||||
name = "tests_test",
|
||||
runtime_deps = [":tests_test_lib"],
|
||||
)
|
||||
### auto-generated section `test intellij.platform.recentFiles.tests` end
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="kotlin-stdlib" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.recentFiles.backend" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.recentFiles.frontend" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.recentFiles" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.recentFiles.plugin" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.libraries.junit5" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.libraries.kotlinx.coroutines.core" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.concurrency" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.impl" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.rpc" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.rpc.backend" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.ui" scope="TEST" />
|
||||
</component>
|
||||
<component name="TestModuleProperties" production-module="intellij.platform.recentFiles.backend" />
|
||||
</module>
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.recentFiles.backend
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.fileEditor.impl.IdeDocumentHistoryImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.recentFiles.frontend.RecentFilesExcluder
|
||||
import com.intellij.platform.recentFiles.frontend.model.FrontendRecentFilesModel
|
||||
import com.intellij.platform.recentFiles.shared.FileChangeKind
|
||||
import com.intellij.platform.recentFiles.shared.RecentFileKind
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.testFramework.junit5.TestDisposable
|
||||
import com.intellij.testFramework.junit5.fixture.projectFixture
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.fail
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@TestApplication
|
||||
class RecentFilesDistributedModelTest {
|
||||
private val projectFixture = projectFixture()
|
||||
private val project by projectFixture
|
||||
|
||||
@TestDisposable
|
||||
lateinit var disposable: Disposable
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
RecentFilesExcluder.EP_NAME.point.registerExtension(TestDiffRecentFilesExcluder(), disposable)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `regular file open and close are synchronized between frontend and backend models`() = runBlocking {
|
||||
withModelSynchronization {
|
||||
val file = LightVirtualFile("regular.txt", "content")
|
||||
val anchorFile1 = LightVirtualFile("anchor1.txt", "content")
|
||||
val anchorFile2 = LightVirtualFile("anchor2.txt", "content")
|
||||
val openedFiles = listOf(file, anchorFile1, anchorFile2)
|
||||
val frontendModel = FrontendRecentFilesModel.getInstance(project)
|
||||
|
||||
frontendModel.applyFrontendChanges(RecentFileKind.RECENTLY_OPENED, openedFiles, FileChangeKind.ADDED)
|
||||
frontendModel.applyFrontendChanges(RecentFileKind.RECENTLY_OPENED_UNPINNED, openedFiles, FileChangeKind.ADDED)
|
||||
|
||||
waitUntilFileIsPresent(file, RecentFileKind.RECENTLY_OPENED)
|
||||
waitUntilFileIsPresent(file, RecentFileKind.RECENTLY_OPENED_UNPINNED)
|
||||
|
||||
frontendModel.applyFrontendChanges(RecentFileKind.RECENTLY_OPENED_UNPINNED, listOf(file), FileChangeKind.REMOVED)
|
||||
|
||||
waitUntilFileIsAbsent(file, RecentFileKind.RECENTLY_OPENED_UNPINNED)
|
||||
assertBothModelsContain(file, RecentFileKind.RECENTLY_OPENED)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `diff file open and close are synchronized between frontend and backend models`() = runBlocking {
|
||||
withModelSynchronization {
|
||||
val file = TestDiffVirtualFile("diff.txt")
|
||||
val frontendModel = FrontendRecentFilesModel.getInstance(project)
|
||||
|
||||
frontendModel.applyFrontendChanges(RecentFileKind.RECENTLY_OPENED, listOf(file), FileChangeKind.ADDED)
|
||||
frontendModel.applyFrontendChanges(RecentFileKind.RECENTLY_OPENED_UNPINNED, listOf(file), FileChangeKind.ADDED)
|
||||
|
||||
waitUntilFileIsPresent(file, RecentFileKind.RECENTLY_OPENED)
|
||||
waitUntilFileIsPresent(file, RecentFileKind.RECENTLY_OPENED_UNPINNED)
|
||||
|
||||
file.isIncludedInHistory = false
|
||||
frontendModel.applyFrontendChanges(RecentFileKind.RECENTLY_OPENED_UNPINNED, listOf(file), FileChangeKind.REMOVED)
|
||||
frontendModel.applyFrontendChanges(RecentFileKind.RECENTLY_OPENED, listOf(file), FileChangeKind.REMOVED)
|
||||
|
||||
waitUntilFileIsAbsent(file, RecentFileKind.RECENTLY_OPENED)
|
||||
waitUntilFileIsAbsent(file, RecentFileKind.RECENTLY_OPENED_UNPINNED)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun withModelSynchronization(action: suspend CoroutineScope.() -> Unit) = coroutineScope {
|
||||
val subscriptions = startModelSynchronization()
|
||||
try {
|
||||
action()
|
||||
}
|
||||
finally {
|
||||
subscriptions.forEach(Job::cancel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun CoroutineScope.startModelSynchronization(): List<Job> {
|
||||
val backendModel = BackendRecentFilesModel.getInstance(project)
|
||||
val frontendModel = FrontendRecentFilesModel.getInstance(project)
|
||||
return RecentFileKind.entries.flatMap { kind ->
|
||||
listOf(
|
||||
launch { backendModel.subscribeToBackendRecentFilesUpdates(kind) },
|
||||
launch { frontendModel.subscribeToBackendRecentFilesUpdates(kind) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun waitUntilFileIsPresent(file: VirtualFile, kind: RecentFileKind) {
|
||||
waitUntil("Expected ${file.name} to appear in $kind") {
|
||||
frontendFiles(kind).contains(file) && backendFiles(kind).contains(file)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun waitUntilFileIsAbsent(file: VirtualFile, kind: RecentFileKind) {
|
||||
var frontendFiles = emptyList<VirtualFile>()
|
||||
var backendFiles = emptyList<VirtualFile>()
|
||||
waitUntil({ "Expected ${file.name} to disappear from $kind, frontend=${frontendFiles.map { it.name }}, backend=${backendFiles.map { it.name }}" }) {
|
||||
frontendFiles = frontendFiles(kind)
|
||||
backendFiles = backendFiles(kind)
|
||||
!frontendFiles.contains(file) && !backendFiles.contains(file)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun assertBothModelsContain(file: VirtualFile, kind: RecentFileKind) {
|
||||
val frontendFiles = frontendFiles(kind)
|
||||
val backendFiles = backendFiles(kind)
|
||||
assertTrue(frontendFiles.contains(file), "Expected frontend $kind to contain ${file.name}, got ${frontendFiles.map { it.name }}")
|
||||
assertTrue(backendFiles.contains(file), "Expected backend $kind to contain ${file.name}, got ${backendFiles.map { it.name }}")
|
||||
}
|
||||
|
||||
private suspend fun waitUntil(message: String, condition: suspend () -> Boolean) {
|
||||
waitUntil({ message }, condition)
|
||||
}
|
||||
|
||||
private suspend fun waitUntil(message: () -> String, condition: suspend () -> Boolean) {
|
||||
try {
|
||||
withTimeout(5.seconds) {
|
||||
while (!condition()) {
|
||||
delay(50.milliseconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (_: TimeoutCancellationException) {
|
||||
fail(message())
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun frontendFiles(kind: RecentFileKind): List<VirtualFile> {
|
||||
return withContext(Dispatchers.EDT) {
|
||||
FrontendRecentFilesModel.getInstance(project).getRecentFiles(kind).mapNotNull { it.virtualFile }
|
||||
}
|
||||
}
|
||||
|
||||
private fun backendFiles(kind: RecentFileKind): List<VirtualFile> {
|
||||
return BackendRecentFilesModel.getInstance(project).getFilesByKind(kind)
|
||||
}
|
||||
|
||||
private class TestDiffVirtualFile(name: String) : LightVirtualFile(name, "diff"), IdeDocumentHistoryImpl.OptionallyIncluded {
|
||||
var isIncludedInHistory: Boolean = true
|
||||
|
||||
override fun isIncludedInDocumentHistory(project: Project): Boolean {
|
||||
return isIncludedInHistory
|
||||
}
|
||||
}
|
||||
|
||||
private class TestDiffRecentFilesExcluder : RecentFilesExcluder {
|
||||
override fun isExcludedFromRecentlyOpened(project: Project, file: VirtualFile): Boolean {
|
||||
return file is TestDiffVirtualFile && !file.isIncludedInDocumentHistory(project)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user