diff --git a/plugins/properties/intellij.properties.iml b/plugins/properties/intellij.properties.iml
index 0dec248b0b90..907ddad6c337 100644
--- a/plugins/properties/intellij.properties.iml
+++ b/plugins/properties/intellij.properties.iml
@@ -21,5 +21,6 @@
+
\ No newline at end of file
diff --git a/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesCharsetTest.java b/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesCharsetTest.java
new file mode 100644
index 000000000000..6667fa894641
--- /dev/null
+++ b/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesCharsetTest.java
@@ -0,0 +1,204 @@
+// 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.lang.properties;
+
+import com.intellij.codeInsight.CodeInsightTestCase;
+import com.intellij.lang.properties.charset.Native2AsciiCharset;
+import com.intellij.lang.properties.psi.PropertiesFile;
+import com.intellij.lang.properties.psi.Property;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.vfs.CharsetToolkit;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.encoding.EncodingManager;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.testFramework.PlatformTestCase;
+import com.intellij.testFramework.PlatformTestUtil;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NonNls;
+
+import java.nio.charset.Charset;
+import java.util.List;
+
+/**
+ * @author cdr
+ */
+@PlatformTestCase.WrapInCommand
+public class PropertiesCharsetTest extends CodeInsightTestCase {
+ private boolean myOldIsNative;
+ private Charset myOldCs;
+ private Charset myOldCharset;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ myOldIsNative = EncodingManager.getInstance().isNative2AsciiForPropertiesFiles();
+ myOldCs = EncodingManager.getInstance().getDefaultCharsetForPropertiesFiles(null);
+ myOldCharset = EncodingManager.getInstance().getDefaultCharset();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ EncodingManager.getInstance().setNative2AsciiForPropertiesFiles(null, myOldIsNative);
+ EncodingManager.getInstance().setDefaultCharsetForPropertiesFiles(null, myOldCs);
+ if (myOldCharset != null) {
+ EncodingManager.getInstance().setDefaultCharsetName(myOldCharset.name());
+ }
+ }
+ finally {
+ super.tearDown();
+ }
+ }
+
+ private void configureByText(@NonNls final String text) throws Exception {
+ myFile = createFile(getTestName(false) + ".properties", text);
+ }
+
+ public void testCharsetOn() throws Exception {
+ EncodingManager.getInstance().setNative2AsciiForPropertiesFiles(null, true);
+
+ configureByText("\\u1234\\uxxxx\\n\\t\\y=\\u3210\\uzzzz\\n\\t\\y");
+ List properties = ((PropertiesFile)myFile).getProperties();
+ assertEquals(1, properties.size());
+ final Property property = (Property)properties.get(0);
+ assertEquals("\u1234\\uxxxx\\n\\t\\y", property.getKey());
+ assertEquals("\u3210\\uzzzz\\n\\t\\y", property.getValue());
+ ApplicationManager.getApplication().runWriteAction(() -> {
+ property.setName("\u041f\\uyyyy\\n\\t\\y");
+ });
+
+ FileDocumentManager.getInstance().saveAllDocuments();
+ VirtualFile virtualFile = myFile.getVirtualFile();
+ // copy to other file type to stop charset mingling
+
+ VirtualFile newFile = copy(virtualFile, virtualFile.getParent(), "xxx.txt");
+ myFilesToDelete.add(VfsUtilCore.virtualToIoFile(newFile));
+ String chars = VfsUtilCore.loadText(newFile);
+ assertEquals("\\u041F\\uyyyy\\n\\t\\y=\\u3210\\uzzzz\\n\\t\\y", chars);
+ }
+
+ public void testCharsetOff() {
+ EncodingManager.getInstance().setNative2AsciiForPropertiesFiles(null, false);
+ EncodingManager.getInstance().setDefaultCharsetForPropertiesFiles(null, Charset.forName("ISO-8859-1"));
+
+ PlatformTestUtil.withEncoding("UTF-8", () -> {
+ configureByText("\\u1234\\uxxxx\\n\\t\\y=\\u3210\\uzzzz\\n\\t\\y");
+ List properties = ((PropertiesFile)myFile).getProperties();
+ assertEquals(1, properties.size());
+ final Property property = (Property)properties.get(0);
+ assertEquals("\\u1234\\uxxxx\\n\\t\\y", property.getKey());
+ assertEquals("\\u3210\\uzzzz\\n\\t\\y", property.getValue());
+ ApplicationManager.getApplication().runWriteAction(() -> {
+ property.setName("\u041f\\uyyyy\\n\\t\\y");
+ });
+
+ FileDocumentManager.getInstance().saveAllDocuments();
+ VirtualFile virtualFile = myFile.getVirtualFile();
+ // copy to other file type to stop charset mingling
+ VirtualFile newFile = copy(virtualFile, virtualFile.getParent(), "xxx.txt");
+ myFilesToDelete.add(VfsUtilCore.virtualToIoFile(newFile));
+ String chars = VfsUtilCore.loadText(newFile);
+ // 0x41f converted to '?' because it cannot be represented in ISO-8859-1
+ assertEquals("?\\uyyyy\\n\\t\\y=\\u3210\\uzzzz\\n\\t\\y", chars);
+ });
+ }
+
+ public void testDefaultCharset() {
+ EncodingManager.getInstance().setNative2AsciiForPropertiesFiles(null, false);
+ EncodingManager.getInstance().setDefaultCharsetForPropertiesFiles(null, null);
+ EncodingManager.getInstance().setEncoding(null, CharsetToolkit.UTF8_CHARSET);
+
+ PlatformTestUtil.withEncoding("UTF-8", () -> {
+ configureByText("\\u1234\\uxxxx\\n\\t\\y=\\u3210\\uzzzz\\n\\t\\y");
+ List properties = ((PropertiesFile)myFile).getProperties();
+ assertEquals(1, properties.size());
+ final Property property = (Property)properties.get(0);
+ assertEquals("\\u1234\\uxxxx\\n\\t\\y", property.getKey());
+ assertEquals("\\u3210\\uzzzz\\n\\t\\y", property.getValue());
+ ApplicationManager.getApplication().runWriteAction(() -> {
+ property.setName("\u041f\\uyyyy\\n\\t\\y");
+ });
+
+ FileDocumentManager.getInstance().saveAllDocuments();
+ VirtualFile virtualFile = myFile.getVirtualFile();
+ // copy to other file type to stop charset mingling
+ VirtualFile newFile = copy(virtualFile, virtualFile.getParent(), "xxx.txt");
+ myFilesToDelete.add(VfsUtilCore.virtualToIoFile(newFile));
+ String chars = VfsUtilCore.loadText(newFile);
+ assertEquals("\u041f\\uyyyy\\n\\t\\y=\\u3210\\uzzzz\\n\\t\\y", chars);
+ });
+ }
+
+ public void testCharsBelow128() throws Exception {
+ EncodingManager.getInstance().setNative2AsciiForPropertiesFiles(null, true);
+ EncodingManager.getInstance().setDefaultCharsetForPropertiesFiles(null, null);
+ EncodingManager.getInstance().setEncoding(null, CharsetToolkit.UTF8_CHARSET);
+
+ configureByText("xxx=\\u3210\\uzzzz\\n\\t\\y");
+ List properties = ((PropertiesFile)myFile).getProperties();
+ assertEquals(1, properties.size());
+ final IProperty property = properties.get(0);
+ ApplicationManager.getApplication().runWriteAction(() -> property.setValue("\u00e7\u007f\u0080\u00ff\u0024"));
+
+ FileDocumentManager.getInstance().saveAllDocuments();
+ VirtualFile virtualFile = myFile.getVirtualFile();
+ // copy to other file type to stop charset mingling
+ VirtualFile newFile = copy(virtualFile, virtualFile.getParent(), "xxx.txt");
+ myFilesToDelete.add(VfsUtilCore.virtualToIoFile(newFile));
+ String chars = VfsUtilCore.loadText(newFile);
+ assertEquals("xxx=\\u00E7\u007F\\u0080\\u00FF\u0024", chars);
+ }
+
+ public void testForceRefresh() throws Exception {
+ EncodingManager.getInstance().setNative2AsciiForPropertiesFiles(null, true);
+ EncodingManager.getInstance().setDefaultCharsetForPropertiesFiles(null, null);
+ EncodingManager.getInstance().setEncoding(null, CharsetToolkit.UTF8_CHARSET);
+ UIUtil.dispatchAllInvocationEvents();
+
+ configureByText("xxx=\\u1234");
+ myEditor = createEditor(myFile.getVirtualFile());
+
+ List properties = ((PropertiesFile)myFile).getProperties();
+ assertEquals(1, properties.size());
+ IProperty property = properties.get(0);
+ assertEquals('\u1234' + "", property.getValue());
+
+ EncodingManager.getInstance().setNative2AsciiForPropertiesFiles(null, false);
+ UIUtil.dispatchAllInvocationEvents();
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+
+ properties = ((PropertiesFile)myFile).getProperties();
+ assertEquals(1, properties.size());
+ property = properties.get(0);
+ assertEquals("\\u1234", property.getValue());
+ }
+
+ public void testChangeEncodingMustReloadFile() throws Exception {
+ EncodingManager.getInstance().setNative2AsciiForPropertiesFiles(null, false);
+ EncodingManager.getInstance().setDefaultCharsetForPropertiesFiles(null, CharsetToolkit.UTF8_CHARSET);
+ UIUtil.dispatchAllInvocationEvents();
+
+ configureByText("xxx=\\u1234");
+ assertEquals(CharsetToolkit.UTF8_CHARSET, myFile.getVirtualFile().getCharset());
+
+ Charset win = Charset.forName("windows-1251");
+ EncodingManager.getInstance().setDefaultCharsetForPropertiesFiles(null, win);
+ UIUtil.dispatchAllInvocationEvents();
+
+ assertEquals(win, myFile.getVirtualFile().getCharset());
+ }
+
+ public void testBOMMarkedFileWithNativeConversion() throws Exception {
+ EncodingManager.getInstance().setNative2AsciiForPropertiesFiles(null, true);
+ EncodingManager.getInstance().setDefaultCharsetForPropertiesFiles(null, CharsetToolkit.UTF8_CHARSET);
+ UIUtil.dispatchAllInvocationEvents();
+
+ VirtualFile file =
+ createTempFile("properties", CharsetToolkit.UTF8_BOM, "general-notice=\\u062a\\u0648\\u062c\\u0647", CharsetToolkit.UTF8_CHARSET);
+ PropertiesFile propertiesFile = (PropertiesFile)getPsiManager().findFile(file);
+ assertNotNull(propertiesFile);
+
+ assertEquals(Native2AsciiCharset.makeNative2AsciiEncodingName(CharsetToolkit.UTF8), file.getCharset().name());
+ }
+}
diff --git a/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesFileTreeStructureTest.java b/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesFileTreeStructureTest.java
new file mode 100644
index 000000000000..e976634832e8
--- /dev/null
+++ b/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesFileTreeStructureTest.java
@@ -0,0 +1,87 @@
+// 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.lang.properties;
+
+import com.intellij.lang.properties.structureView.GroupByWordPrefixes;
+import com.intellij.lang.properties.structureView.PropertiesFileStructureViewModel;
+import com.intellij.testFramework.PlatformTestUtil;
+import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
+import com.intellij.util.ui.tree.TreeUtil;
+
+public class PropertiesFileTreeStructureTest extends LightPlatformCodeInsightFixtureTestCase {
+ public void testGrouping() {
+ doTest("a.b.c=dddd\n" +
+ "a.b.d=dddd\n" +
+ "a.x=i\n" +
+ "b.n.p=ooo",
+
+ "Test.properties\n" +
+ " a\n" +
+ " b\n" +
+ " c\n" +
+ " d\n" +
+ " x\n" +
+ " b.n.p\n");
+ }
+
+ public void testNesting() {
+ doTest("a=dddd\n" +
+ "a.b=dddd\n" +
+ "a.b.c=i\n" +
+ "a.b.c.d=ooo",
+
+ "Test.properties\n" +
+ " a\n" +
+ " \n" +
+ " b\n" +
+ " \n" +
+ " c\n" +
+ " \n" +
+ " d\n");
+ }
+
+ public void testGroupSort() {
+ doTest("log4j.category.x=dd\n" +
+ "log4j.category.xdo=dd\n" +
+ "log4j.category.middlegen.swing.ss=dd\n" +
+ "log4j.category.middlegen.plugins.ss=dd\n" +
+ "log4j.appender.middlegen.plugins.ss=dd",
+
+ "Test.properties\n" +
+ " log4j\n" +
+ " appender.middlegen.plugins.ss\n" +
+ " category\n" +
+ " middlegen\n" +
+ " plugins.ss\n" +
+ " swing.ss\n" +
+ " x\n" +
+ " xdo\n");
+ }
+
+ public void testFunkyGroups() {
+ doTest("errors.byte={0} must be a BYTE type \n" +
+ "errors.short={0} must be a SHORT type \n" +
+ "error.date={0} must be a DATE types \n" +
+ "error.range={0} is not between {1} and {2} \n" +
+ "errors.email={0} is not a valid Email Address \n" +
+ "errors.ipaddress={0} is not a valid IP address",
+
+ "Test.properties\n" +
+ " error\n" +
+ " date\n" +
+ " range\n" +
+ " errors\n" +
+ " byte\n" +
+ " email\n" +
+ " ipaddress\n" +
+ " short\n");
+ }
+
+ private void doTest(String classText, String expected) {
+ myFixture.configureByText("Test.properties", classText);
+ myFixture.testStructureView(svc -> {
+ svc.setActionActive(GroupByWordPrefixes.ID, true);
+ svc.setActionActive(PropertiesFileStructureViewModel.KIND_SORTER_ID, true);
+ TreeUtil.expandAll(svc.getTree(), () -> PlatformTestUtil.assertTreeStructureEquals(svc.getTree().getModel(), expected));
+ });
+ }
+}