diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test.xml b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test.xml
new file mode 100644
index 000000000000..463f9f8e9c4c
--- /dev/null
+++ b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test/c.png b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test/c.png
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test/c1.png b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test/c1.png
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test/shelved.patch b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test/shelved.patch
new file mode 100644
index 000000000000..66d1a5a3b505
--- /dev/null
+++ b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test/shelved.patch
@@ -0,0 +1,12 @@
+--- 1.txt
++++ 1.txt
+@@ -0,0 +1,3 @@
++One
++Two
++Three
+--- 2.txt
++++ 2.txt
+@@ -0,0 +1,3 @@
++One
++Two
++Three
\ No newline at end of file
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test1.xml b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test1.xml
new file mode 100644
index 000000000000..ef4d02f8510c
--- /dev/null
+++ b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test1.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test1/c.png b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test1/c.png
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test1/c1.png b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test1/c1.png
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test1/shelved.patch b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test1/shelved.patch
new file mode 100644
index 000000000000..66d1a5a3b505
--- /dev/null
+++ b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test1/shelved.patch
@@ -0,0 +1,12 @@
+--- 1.txt
++++ 1.txt
+@@ -0,0 +1,3 @@
++One
++Two
++Three
+--- 2.txt
++++ 2.txt
+@@ -0,0 +1,3 @@
++One
++Two
++Three
\ No newline at end of file
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test2.xml b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test2.xml
new file mode 100644
index 000000000000..602e36779abb
--- /dev/null
+++ b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test2.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test2/c.png b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test2/c.png
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test2/c1.png b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test2/c1.png
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/platform/vcs-tests/testData/shelf/shelvedChangeLists/test2/shelved.patch b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test2/shelved.patch
new file mode 100644
index 000000000000..66d1a5a3b505
--- /dev/null
+++ b/platform/vcs-tests/testData/shelf/shelvedChangeLists/test2/shelved.patch
@@ -0,0 +1,12 @@
+--- 1.txt
++++ 1.txt
+@@ -0,0 +1,3 @@
++One
++Two
++Three
+--- 2.txt
++++ 2.txt
+@@ -0,0 +1,3 @@
++One
++Two
++Three
\ No newline at end of file
diff --git a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManagerTest.kt b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManagerTest.kt
new file mode 100644
index 000000000000..efeb8b380413
--- /dev/null
+++ b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManagerTest.kt
@@ -0,0 +1,134 @@
+// 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.openapi.vcs.changes.shelf
+
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.io.FileUtil
+import com.intellij.openapi.vcs.VcsTestUtil
+import com.intellij.testFramework.PlatformTestCase
+import junit.framework.TestCase
+import java.io.File
+import java.nio.file.Path
+
+class ShelveChangesManagerTest : PlatformTestCase() {
+ private lateinit var myShelvedChangesManager: ShelveChangesManager
+
+ override fun doCreateProject(projectFile: Path): Project {
+ val project = super.doCreateProject(projectFile)
+ val testDataFile = File("${VcsTestUtil.getTestDataPath()}/shelf/shelvedChangeLists")
+ val shelfFile = File("${project.basePath}/.shelf")
+ FileUtil.createDirectory(shelfFile)
+ myFilesToDelete.add(shelfFile)
+ testDataFile.copyRecursively(shelfFile)
+ return project
+ }
+
+ override fun setUp() {
+ super.setUp()
+ myShelvedChangesManager = ShelveChangesManager.getInstance(myProject)
+ }
+
+ fun `test unshelve list`() {
+ doTestUnshelve(0, 0, 2, 1)
+ }
+
+ fun `test unshelve files`() {
+ doTestUnshelve(1, 1, 3, 1)
+ }
+
+ fun `test unshelve all files`() {
+ doTestUnshelve(2, 2, 2, 1)
+ }
+
+ fun `test do not remove files when unshelve`() {
+ doTestUnshelve(0, 0, 3, 0, false)
+ }
+
+ fun `test delete list`() {
+ doTestDelete(myShelvedChangesManager.shelvedChangeLists[0], 0, 0, 2, 1)
+ }
+
+ fun `test delete files`() {
+ doTestDelete(myShelvedChangesManager.shelvedChangeLists[0], 1, 1, 3, 1)
+ }
+
+ fun `test delete all files`() {
+ doTestDelete(myShelvedChangesManager.shelvedChangeLists[0], 2, 2, 2, 1)
+ }
+
+ fun `test delete deleted list`() {
+ val shelvedChangeList = myShelvedChangesManager.shelvedChangeLists[0]
+ myShelvedChangesManager.deleteChangeList(shelvedChangeList)
+ doTestDelete(shelvedChangeList, 0, 0, 2, 0)
+ }
+
+ fun `test delete deleted files`() {
+ val shelvedChangeList = myShelvedChangesManager.shelvedChangeLists[0]
+ myShelvedChangesManager.deleteChangeList(shelvedChangeList)
+ doTestDelete(shelvedChangeList, 1, 1, 2, 1)
+ }
+
+ fun `test delete all deleted files`() {
+ val shelvedChangeList = myShelvedChangesManager.shelvedChangeLists[0]
+ myShelvedChangesManager.deleteChangeList(shelvedChangeList)
+ doTestDelete(shelvedChangeList, 2, 2, 2, 0)
+ }
+
+ fun `test undo list deletion`() {
+ doTestDelete(myShelvedChangesManager.shelvedChangeLists[0], 0, 0, 2, 1, true)
+ }
+
+ fun `test undo file deletion`() {
+ //correct undo depends on ability to merge 2 shelved lists with separated changes inside
+ doTestDelete(myShelvedChangesManager.shelvedChangeLists[0], 1, 1, 3, 1, true)
+ }
+
+ private fun doTestUnshelve(changesNum: Int,
+ binariesNum: Int,
+ expectedListNum: Int,
+ expectedRecycledNum: Int,
+ removeFilesFromShelf: Boolean = true) {
+ myShelvedChangesManager.isRemoveFilesFromShelf = removeFilesFromShelf
+ val shelvedChangeList = myShelvedChangesManager.shelvedChangeLists[0]
+ val originalDate = shelvedChangeList.DATE
+ val changes = if (changesNum == 0) null else shelvedChangeList.getChanges(myProject).subList(0, changesNum)
+ val binaries = if (changesNum == 0) null else shelvedChangeList.binaryFiles.subList(0, binariesNum)
+
+ myShelvedChangesManager.unshelveChangeList(shelvedChangeList, changes, binaries, null, false)
+ val recycledShelvedChangeLists = myShelvedChangesManager.recycledShelvedChangeLists
+ TestCase.assertEquals(expectedListNum, myShelvedChangesManager.shelvedChangeLists.size)
+ TestCase.assertEquals(expectedRecycledNum, recycledShelvedChangeLists.size)
+ if (recycledShelvedChangeLists.isNotEmpty())
+ assertTrue(originalDate.before(recycledShelvedChangeLists[0].DATE))
+ }
+
+ private fun doTestDelete(shelvedChangeList: ShelvedChangeList,
+ changesNum: Int,
+ binariesNum: Int,
+ expectedListNum: Int,
+ expectedDeletedNum: Int,
+ undoDeletion: Boolean = false) {
+ val originalDate = shelvedChangeList.DATE
+ val changes = if (changesNum == 0) emptyList() else shelvedChangeList.getChanges(myProject).subList(0, changesNum)
+ val binaries = if (changesNum == 0) emptyList() else shelvedChangeList.binaryFiles.subList(0, binariesNum)
+
+ val shouldDeleteEntireList = changesNum == 0 && binariesNum == 0
+ val deleteShelvesWithDates = myShelvedChangesManager.deleteShelves(
+ if (shouldDeleteEntireList) listOf(shelvedChangeList) else emptyList(),
+ if (!shouldDeleteEntireList) listOf(shelvedChangeList) else emptyList(),
+ changes, binaries)
+
+ val deletedLists = myShelvedChangesManager.deletedLists
+ TestCase.assertEquals(expectedListNum, myShelvedChangesManager.shelvedChangeLists.size)
+ TestCase.assertEquals(expectedDeletedNum, deletedLists.size)
+ if (deletedLists.isNotEmpty() && deleteShelvesWithDates.isNotEmpty())
+ assertTrue(originalDate.before(deletedLists[0].DATE))
+
+ if (undoDeletion) {
+ deleteShelvesWithDates.forEach { l, d -> myShelvedChangesManager.restoreList(l, d) }
+ TestCase.assertEquals(expectedListNum + expectedDeletedNum, myShelvedChangesManager.shelvedChangeLists.size)
+ }
+ }
+}
+
+
+