From d5979ffdedb3c9f8330c15350f1916d8e0949e37 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Fri, 27 Nov 2020 20:25:16 +0100 Subject: [PATCH] FIR IDE: add tests for checking module invalidation --- .../kotlin/generators/tests/GenerateTests.kt | 4 + .../KotlinFirOutOfBlockModificationTracker.kt | 7 ++ .../binaryTree/structure.json | 14 +++ .../binaryTreeNoInvalidated/structure.json | 14 +++ .../structure.json | 14 +++ .../structure.json | 14 +++ .../sessionInvalidation/linear/structure.json | 12 ++ .../rhombus/structure.json | 11 ++ .../rhombusWithTwoInvalid/structure.json | 11 ++ .../fir/low/level/api/TestProjectStructure.kt | 6 + .../idea/fir/low/level/api/firTestUtils.kt | 7 ++ .../AbstractSessionsInvalidationTest.kt | 107 ++++++++++++++++++ .../SessionsInvalidationTestGenerated.java | 65 +++++++++++ 13 files changed, 286 insertions(+) create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTree/structure.json create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeNoInvalidated/structure.json create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeWithAdditionalEdge/structure.json create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeWithInvalidInRoot/structure.json create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/linear/structure.json create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/rhombus/structure.json create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/rhombusWithTwoInvalid/structure.json create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/AbstractSessionsInvalidationTest.kt create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/SessionsInvalidationTestGenerated.java diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index f2c688a2d36..6534ab2f8e4 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -85,6 +85,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirLazyDeclarationRes import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirMultiModuleLazyResolveTest import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.AbstractFileStructureTest import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.AbstractFileStructureAndOutOfBlockModificationTrackerConsistencyTest +import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.AbstractSessionsInvalidationTest import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest import org.jetbrains.kotlin.idea.frontend.api.fir.AbstractResolveCallTest import org.jetbrains.kotlin.idea.fir.low.level.api.trackers.AbstractProjectWideOutOfBlockKotlinModificationTrackerTest @@ -1049,6 +1050,9 @@ fun main(args: Array) { testClass { model("fileStructure") } + testClass { + model("sessionInvalidation", recursive = false, extension = null) + } } testGroup("idea/idea-fir/tests", "idea") { diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/trackers/KotlinFirOutOfBlockModificationTracker.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/trackers/KotlinFirOutOfBlockModificationTracker.kt index 0c47acf9818..7a3ddd10fd3 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/trackers/KotlinFirOutOfBlockModificationTracker.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/trackers/KotlinFirOutOfBlockModificationTracker.kt @@ -18,6 +18,7 @@ import com.intellij.pom.event.PomModelEvent import com.intellij.pom.event.PomModelListener import com.intellij.pom.tree.TreeAspect import com.intellij.pom.tree.events.TreeChangeEvent +import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingInBodyDeclarationWith import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileElementFactory @@ -45,6 +46,12 @@ internal class KotlinFirModificationTrackerService(project: Project) : Disposabl moduleModificationsState.increaseModificationCountForAllModules() } + @TestOnly + fun increaseModificationCountForModule(module: Module) { + moduleModificationsState.increaseModificationCountForModule(module) + } + + private fun subscribeForRootChanges(project: Project) { project.messageBus.connect(this).subscribe( ProjectTopics.PROJECT_ROOTS, diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTree/structure.json b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTree/structure.json new file mode 100644 index 00000000000..19e8f739669 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTree/structure.json @@ -0,0 +1,14 @@ +{ + "modules" : [ + { "name": "A", "dependsOn": ["B", "C"] }, + { "name": "B", "dependsOn": ["D", "E"] }, + { "name": "C", "dependsOn": ["F", "G"] }, + { "name": "D", "dependsOn": [] }, + { "name": "E", "dependsOn": [] }, + { "name": "F", "dependsOn": [] }, + { "name": "G", "dependsOn": [] } + ], + "rootModule": "A", + "modulesToMakeOOBM": ["F"], + "expectedInvalidatedModules": ["A", "C", "F"] +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeNoInvalidated/structure.json b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeNoInvalidated/structure.json new file mode 100644 index 00000000000..ef47e4c728e --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeNoInvalidated/structure.json @@ -0,0 +1,14 @@ +{ + "modules" : [ + { "name": "A", "dependsOn": ["B", "C"] }, + { "name": "B", "dependsOn": ["D", "E"] }, + { "name": "C", "dependsOn": ["F", "G"] }, + { "name": "D", "dependsOn": [] }, + { "name": "E", "dependsOn": [] }, + { "name": "F", "dependsOn": [] }, + { "name": "G", "dependsOn": [] } + ], + "rootModule": "A", + "modulesToMakeOOBM": [], + "expectedInvalidatedModules": [] +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeWithAdditionalEdge/structure.json b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeWithAdditionalEdge/structure.json new file mode 100644 index 00000000000..3f37c42fa75 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeWithAdditionalEdge/structure.json @@ -0,0 +1,14 @@ +{ + "modules" : [ + { "name": "A", "dependsOn": ["B", "C"] }, + { "name": "B", "dependsOn": ["D", "E"] }, + { "name": "C", "dependsOn": ["F", "G"] }, + { "name": "D", "dependsOn": [] }, + { "name": "E", "dependsOn": [] }, + { "name": "F", "dependsOn": ["B"] }, + { "name": "G", "dependsOn": [] } + ], + "rootModule": "A", + "modulesToMakeOOBM": ["E"], + "expectedInvalidatedModules": ["A", "B", "C", "E", "F"] +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeWithInvalidInRoot/structure.json b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeWithInvalidInRoot/structure.json new file mode 100644 index 00000000000..c85989c8dd2 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeWithInvalidInRoot/structure.json @@ -0,0 +1,14 @@ +{ + "modules" : [ + { "name": "A", "dependsOn": ["B", "C"] }, + { "name": "B", "dependsOn": ["D", "E"] }, + { "name": "C", "dependsOn": ["F", "G"] }, + { "name": "D", "dependsOn": [] }, + { "name": "E", "dependsOn": [] }, + { "name": "F", "dependsOn": [] }, + { "name": "G", "dependsOn": [] } + ], + "rootModule": "A", + "modulesToMakeOOBM": ["A"], + "expectedInvalidatedModules": ["A"] +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/linear/structure.json b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/linear/structure.json new file mode 100644 index 00000000000..a5a7b0ec05a --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/linear/structure.json @@ -0,0 +1,12 @@ +{ + "modules" : [ + { "name": "A", "dependsOn": ["B"] }, + { "name": "B", "dependsOn": ["C"] }, + { "name": "C", "dependsOn": ["D"] }, + { "name": "D", "dependsOn": ["E"] }, + { "name": "E", "dependsOn": [] } + ], + "rootModule": "A", + "modulesToMakeOOBM": ["C"], + "expectedInvalidatedModules": ["A", "B", "C"] +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/rhombus/structure.json b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/rhombus/structure.json new file mode 100644 index 00000000000..0a76c3f8d05 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/rhombus/structure.json @@ -0,0 +1,11 @@ +{ + "modules" : [ + { "name": "A", "dependsOn": ["B", "C"] }, + { "name": "B", "dependsOn": ["D"] }, + { "name": "C", "dependsOn": ["D"] }, + { "name": "D", "dependsOn": [] } + ], + "rootModule": "A", + "modulesToMakeOOBM": ["D"], + "expectedInvalidatedModules": ["A", "B", "C", "D"] +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/rhombusWithTwoInvalid/structure.json b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/rhombusWithTwoInvalid/structure.json new file mode 100644 index 00000000000..9ce45934178 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/rhombusWithTwoInvalid/structure.json @@ -0,0 +1,11 @@ +{ + "modules" : [ + { "name": "A", "dependsOn": ["B", "C"] }, + { "name": "B", "dependsOn": ["D"] }, + { "name": "C", "dependsOn": ["D"] }, + { "name": "D", "dependsOn": [] } + ], + "rootModule": "A", + "modulesToMakeOOBM": ["C", "D"], + "expectedInvalidatedModules": ["A", "B", "C", "D"] +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/TestProjectStructure.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/TestProjectStructure.kt index 0cdb8141b1e..a8e7834c69f 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/TestProjectStructure.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/TestProjectStructure.kt @@ -55,4 +55,10 @@ internal object TestProjectStructureReader { val json = JsonParser().parse(FileUtil.loadFile(jsonFile.toFile(), /*convertLineSeparators=*/true)) return TestProjectStructure.parse(json) } + + fun readToTestStructure( + testDirectory: Path, + jsonFileName: String = "structure.json", + toTestStructure: (TestProjectStructure) -> T, + ): T = read(testDirectory, jsonFileName).let(toTestStructure) } \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/firTestUtils.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/firTestUtils.kt index 32066cdbbed..25cf2103fcc 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/firTestUtils.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/firTestUtils.kt @@ -5,10 +5,13 @@ package org.jetbrains.kotlin.idea.fir.low.level.api +import com.intellij.openapi.components.service +import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.Project import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState +import org.jetbrains.kotlin.idea.fir.low.level.api.trackers.KotlinFirModificationTrackerService import org.jetbrains.kotlin.psi.KtElement internal fun Project.allModules() = ModuleManager.getInstance(this).modules.toList() @@ -16,4 +19,8 @@ internal fun Project.allModules() = ModuleManager.getInstance(this).modules.toLi inline fun resolveWithClearCaches(context: KtElement, action: (FirModuleResolveState) -> Unit) { val resolveState = createResolveStateForNoCaching(context.getModuleInfo()) action(resolveState) +} + +internal fun Module.incModificationTracker() { + project.service().increaseModificationCountForModule(this) } \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/AbstractSessionsInvalidationTest.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/AbstractSessionsInvalidationTest.kt new file mode 100644 index 00000000000..7b7045dfb6c --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/AbstractSessionsInvalidationTest.kt @@ -0,0 +1,107 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.fir.low.level.api.sessions + +import com.google.common.collect.Sets +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.module.Module +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.testFramework.PsiTestUtil +import junit.framework.Assert +import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo +import org.jetbrains.kotlin.idea.caches.project.productionSourceInfo +import org.jetbrains.kotlin.idea.fir.low.level.api.TestProjectModule +import org.jetbrains.kotlin.idea.fir.low.level.api.TestProjectStructure +import org.jetbrains.kotlin.idea.fir.low.level.api.TestProjectStructureReader +import org.jetbrains.kotlin.idea.fir.low.level.api.incModificationTracker +import org.jetbrains.kotlin.idea.jsonUtils.getString +import org.jetbrains.kotlin.idea.stubs.AbstractMultiModuleTest +import org.jetbrains.kotlin.test.KotlinTestUtils +import java.nio.file.Files +import java.nio.file.Paths +import kotlin.io.path.writeText + +abstract class AbstractSessionsInvalidationTest : AbstractMultiModuleTest() { + override fun getTestDataPath(): String = + "${KotlinTestUtils.getHomeDirectory()}/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/" + + protected fun doTest(path: String) { + val testStructure = TestProjectStructureReader.readToTestStructure( + Paths.get(path), + toTestStructure = MultiModuleTestProjectStructure.Companion::fromTestProjectStructure + ) + val modulesByNames = testStructure.modules.associate { moduleData -> + moduleData.name to createEmptyModule(moduleData.name) + } + testStructure.modules.forEach { moduleData -> + val module = modulesByNames.getValue(moduleData.name) + moduleData.dependsOnModules.forEach { dependencyName -> + module.addDependency(modulesByNames.getValue(dependencyName)) + } + } + + val rootModule = modulesByNames[testStructure.rootModule] + ?: error("${testStructure.rootModule} is not present in the list of modules") + val modulesToMakeOOBM = testStructure.modulesToMakeOOBM.map { + modulesByNames[it] + ?: error("$it is not present in the list of modules") + } + + val rootModuleSourceInfo = rootModule.productionSourceInfo()!! + + val storage = FirIdeSessionProviderStorage(project) + + val initialSessions = storage.getFirSessions(rootModuleSourceInfo) + modulesToMakeOOBM.forEach { it.incModificationTracker() } + val sessionsAfterOOBM = storage.getFirSessions(rootModuleSourceInfo) + + val changedSessions = Sets.symmetricDifference(initialSessions, sessionsAfterOOBM) + val changedSessionsModulesNamesSorted = changedSessions.map { (it.moduleInfo as ModuleSourceInfo).module.name }.distinct().sorted() + + Assert.assertEquals(testStructure.expectedInvalidatedModules, changedSessionsModulesNamesSorted) + } + + private fun FirIdeSessionProviderStorage.getFirSessions(rootModuleInfo: ModuleSourceInfo): Set { + val sessionProvider = getSessionProvider(rootModuleInfo) + return sessionProvider.sessions.values.toSet() + } + + private fun createEmptyModule(name: String): Module { + val tmpDir = createTempDirectory().toPath() + val module: Module = createModule("$tmpDir/$name", moduleType) + val root = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tmpDir.toFile())!! + WriteCommandAction.writeCommandAction(module.project).run { + root.refresh(false, true) + } + + PsiTestUtil.addSourceContentToRoots(module, root) + return module + } +} + +private data class MultiModuleTestProjectStructure( + val modules: List, + val rootModule: String, + val modulesToMakeOOBM: List, + val expectedInvalidatedModules: List, +) { + companion object { + fun fromTestProjectStructure(testProjectStructure: TestProjectStructure): MultiModuleTestProjectStructure { + val json = testProjectStructure.json + + return MultiModuleTestProjectStructure( + testProjectStructure.modules, + json.getString(ROOT_MODULE_FIELD), + json.getAsJsonArray(MODULES_TO_MAKE_OOBM_IN_FIELD).map { it.asString }.sorted(), + json.getAsJsonArray(EXPECTED_INVALIDATED_MODULES_FIELD).map { it.asString }.sorted(), + ) + } + + private const val ROOT_MODULE_FIELD = "rootModule" + private const val MODULES_TO_MAKE_OOBM_IN_FIELD = "modulesToMakeOOBM" + private const val EXPECTED_INVALIDATED_MODULES_FIELD = "expectedInvalidatedModules" + } +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/SessionsInvalidationTestGenerated.java b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/SessionsInvalidationTestGenerated.java new file mode 100644 index 00000000000..eabea64952c --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/SessionsInvalidationTestGenerated.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.fir.low.level.api.sessions; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class SessionsInvalidationTestGenerated extends AbstractSessionsInvalidationTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInSessionInvalidation() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation"), Pattern.compile("^([^\\.]+)$"), null, false); + } + + @TestMetadata("binaryTree") + public void testBinaryTree() throws Exception { + runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTree/"); + } + + @TestMetadata("binaryTreeNoInvalidated") + public void testBinaryTreeNoInvalidated() throws Exception { + runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeNoInvalidated/"); + } + + @TestMetadata("binaryTreeWithAdditionalEdge") + public void testBinaryTreeWithAdditionalEdge() throws Exception { + runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeWithAdditionalEdge/"); + } + + @TestMetadata("binaryTreeWithInvalidInRoot") + public void testBinaryTreeWithInvalidInRoot() throws Exception { + runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/binaryTreeWithInvalidInRoot/"); + } + + @TestMetadata("linear") + public void testLinear() throws Exception { + runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/linear/"); + } + + @TestMetadata("rhombus") + public void testRhombus() throws Exception { + runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/rhombus/"); + } + + @TestMetadata("rhombusWithTwoInvalid") + public void testRhombusWithTwoInvalid() throws Exception { + runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/sessionInvalidation/rhombusWithTwoInvalid/"); + } +}