[workspace model] WM-T-57 Update facet xml config in the store before commit

Prior to this fix, we don't have actual state of facet config in the store because it was serialized
only once at `ModifiableFacetModelBridge#addFacet`. But for example in Kotlin plugin, facet configuration
changed before the model commit at maven project import `MavenProjectImportHandler#configureFacet` and
these changes weren't reflected in the store.

GitOrigin-RevId: ec1227b91f87b440f4a58336598ab4feda4f9c57
This commit is contained in:
Mikhail Mazurkevich
2020-06-16 14:49:25 +03:00
committed by intellij-monorepo-bot
parent 2826cb4cdd
commit 75d2e2cd58
3 changed files with 117 additions and 0 deletions
@@ -104,6 +104,19 @@ public class FacetManagerTest extends FacetTestCase {
commit(model);
assertNull(getFacetManager().getFacetByType(MockFacetType.ID));
}
public void testChangeFacetConfiguration() {
String configData = "data";
ModifiableFacetModel model = getFacetManager().createModifiableModel();
MockFacet mockFacet = new MockFacet(myModule, "mock");
model.addFacet(mockFacet);
mockFacet.getConfiguration().setData(configData);
commit(model);
MockFacet facetByType = getFacetManager().getFacetByType(MockFacetType.ID);
assertEquals(configData, facetByType.getConfiguration().getData());
assertSame(mockFacet, facetByType);
}
public void testAddRemoveFacetWithSubFacet() {
assertNull(getFacetManager().getFacetByType(MockSubFacetType.ID));
@@ -98,6 +98,7 @@ internal class ModifiableFacetModelBridge(private val initialStorage: WorkspaceE
override fun commit() {
val moduleDiff = moduleBridge.diff
updateFacetConfiguration()
if (moduleDiff != null) {
val res = moduleDiff.addDiff(diff)
populateModel(res)
@@ -110,6 +111,19 @@ internal class ModifiableFacetModelBridge(private val initialStorage: WorkspaceE
}
}
// In some cases configuration for newly added facets changes before the actual commit e.g. MavenProjectImportHandler#configureFacet.
private fun updateFacetConfiguration() {
entityToFacet.forEach { (facetEntity, facet) ->
if (initialStorage.resolve(facetEntity.persistentId()) != null) return@forEach
val newFacetConfiguration = FacetUtil.saveFacetConfiguration(facet)?.let { JDOMUtil.write(it) }
if (facetEntity.configurationXmlTag == newFacetConfiguration) return@forEach
val newEntity = diff.modifyEntity(ModifiableFacetEntity::class.java, facetEntity) {
this.configurationXmlTag = newFacetConfiguration
}
entityToFacet.inverse()[facet] = newEntity
}
}
private fun populateModel(replaceMap: Map<WorkspaceEntity, WorkspaceEntity>) {
val mapInNewStore: HashBiMap<FacetEntity, Facet<*>> = HashBiMap.create()
entityToFacet.forEach { (key, value) -> mapInNewStore[replaceMap.getOrDefault(key, key) as FacetEntity] = value }
@@ -0,0 +1,90 @@
// Copyright 2000-2020 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.workspaceModel.ide
import com.intellij.facet.FacetManager
import com.intellij.facet.FacetType
import com.intellij.facet.impl.FacetUtil
import com.intellij.facet.mock.MockFacet
import com.intellij.facet.mock.MockFacetType
import com.intellij.openapi.application.runWriteActionAndWait
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.module.EmptyModuleType
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.JDOMUtil
import com.intellij.testFramework.ApplicationRule
import com.intellij.testFramework.DisposableRule
import com.intellij.testFramework.TemporaryDirectory
import com.intellij.workspaceModel.ide.impl.legacyBridge.facet.ModifiableFacetModelBridge
import com.intellij.workspaceModel.ide.legacyBridge.ModuleBridge
import com.intellij.workspaceModel.storage.bridgeEntities.FacetEntity
import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import java.io.File
class FacetModelBridgeTest {
@Rule
@JvmField
var application = ApplicationRule()
@Rule
@JvmField
var temporaryDirectoryRule = TemporaryDirectory()
@Rule
@JvmField
var disposableRule = DisposableRule()
private lateinit var project: Project
private lateinit var module: Module
@Before
fun prepareProject() {
project = createEmptyTestProject(temporaryDirectoryRule, disposableRule)
module = createModule()
FacetType.EP_NAME.point.registerExtension(MockFacetType(), module)
}
@Test
fun `test changed facet config saved correctly`() = WriteCommandAction.runWriteCommandAction(project) {
val facetData = "mock"
val facet = MockFacet(module, facetData)
getFacetManager().createModifiableModel().let { modifiableModel ->
modifiableModel.addFacet(facet)
Assert.assertTrue(facet.configuration.data.isEmpty())
facet.configuration.data = facetData
modifiableModel.commit()
}
val facetConfigXml = FacetUtil.saveFacetConfiguration(facet)?.let { JDOMUtil.write(it) }
val facetByType = getFacetManager().getFacetByType(MockFacetType.ID)
assertNotNull(facetByType)
assertEquals(facetData, facetByType!!.configuration.data)
val entityStorage = WorkspaceModel.getInstance(project).entityStorage
val facetEntity = entityStorage.current.entities(FacetEntity::class.java).first()
assertEquals(facetConfigXml, facetEntity.configurationXmlTag)
getFacetManager().createModifiableModel().let { modifiableModel ->
modifiableModel as ModifiableFacetModelBridge
assertEquals(facetConfigXml, modifiableModel.getEntity(facet)!!.configurationXmlTag)
}
}
private fun createModule(): Module = runWriteActionAndWait {
ModuleManager.getInstance(project).modifiableModel.let { moduleModel ->
val module = moduleModel.newModule(File(project.basePath, "test.iml").path, EmptyModuleType.getInstance().id) as ModuleBridge
moduleModel.commit()
module
}
}
private fun getFacetManager(): FacetManager {
return FacetManager.getInstance(module)
}
}