Do not convert separatorsToSystem in file path extensions.

Do not require network host in network share root to contain dot.
File.root now is always non-null to be consistent with File.toComponents().root.
Introduce invariantSeparatorsPath property.
Deprecate relativeTo to make it return File later. Introduce toRelativeString instead.
Introduce relativeToOrNull and relativeToOrSelf extensions.
This commit is contained in:
Ilya Gorbunov
2015-12-10 01:26:01 +03:00
parent 52eb9e4276
commit 7c9b53c75c
4 changed files with 186 additions and 117 deletions
+25 -33
View File
@@ -11,7 +11,6 @@ class FileTreeWalkTest {
companion object {
val referenceFilenames =
listOf("1", "1/2", "1/3", "1/3/4.txt", "1/3/5.txt", "6", "7.txt", "8", "8/9.txt")
.map { it.separatorsToSystem() }
fun createTestFiles(): File {
val basedir = createTempDir()
for (name in referenceFilenames) {
@@ -31,14 +30,14 @@ class FileTreeWalkTest {
val referenceNames = setOf("") + referenceFilenames
val namesTopDown = HashSet<String>()
for (file in basedir.walkTopDown()) {
val name = file.relativeTo(basedir)
val name = file.relativeToOrSelf(basedir).invariantSeparatorsPath
assertFalse(namesTopDown.contains(name), "$name is visited twice")
namesTopDown.add(name)
}
assertEquals(referenceNames, namesTopDown)
val namesBottomUp = HashSet<String>()
for (file in basedir.walkBottomUp()) {
val name = file.relativeTo(basedir)
val name = file.relativeToOrSelf(basedir).invariantSeparatorsPath
assertFalse(namesBottomUp.contains(name), "$name is visited twice")
namesBottomUp.add(name)
}
@@ -69,13 +68,12 @@ class FileTreeWalkTest {
val basedir = createTestFiles()
try {
val referenceNames =
listOf("", "1", "1/2", "6", "8").map(
{ it -> it.separatorsToSystem() }).toHashSet()
setOf("", "1", "1/2", "6", "8")
val namesTopDownEnter = HashSet<String>()
val namesTopDownLeave = HashSet<String>()
val namesTopDown = HashSet<String>()
fun enter(file: File): Boolean {
val name = file.relativeTo(basedir)
val name = file.relativeToOrSelf(basedir).invariantSeparatorsPath
assertTrue(file.isDirectory, "$name is not directory, only directories should be entered")
assertFalse(namesTopDownEnter.contains(name), "$name is entered twice")
assertFalse(namesTopDownLeave.contains(name), "$name is left before entrance")
@@ -85,7 +83,7 @@ class FileTreeWalkTest {
}
fun leave(file: File) {
val name = file.relativeTo(basedir)
val name = file.relativeToOrSelf(basedir).invariantSeparatorsPath
assertTrue(file.isDirectory, "$name is not directory, only directories should be left")
assertFalse(namesTopDownLeave.contains(name), "$name is left twice")
namesTopDownLeave.add(name)
@@ -93,7 +91,7 @@ class FileTreeWalkTest {
}
fun visit(file: File) {
val name = file.relativeTo(basedir)
val name = file.relativeToOrSelf(basedir).invariantSeparatorsPath
if (file.isDirectory) {
assertTrue(namesTopDownEnter.contains(name), "$name is visited before entrance")
namesTopDown.add(name)
@@ -103,7 +101,7 @@ class FileTreeWalkTest {
return
val parent = file.parentFile
if (parent != null) {
val parentName = parent.relativeTo(basedir)
val parentName = parent.relativeToOrSelf(basedir).invariantSeparatorsPath
assertTrue(namesTopDownEnter.contains(parentName),
"$name is visited before entering its parent $parentName")
assertFalse(namesTopDownLeave.contains(parentName),
@@ -131,11 +129,9 @@ class FileTreeWalkTest {
@Test fun withFilterAndMap() {
val basedir = createTestFiles()
try {
val referenceNames =
listOf("", "1", "1/2", "1/3", "6", "8").map(
{ it -> it.separatorsToSystem() }).toHashSet()
val referenceNames = setOf("", "1", "1/2", "1/3", "6", "8")
assertEquals(referenceNames, basedir.walkTopDown().filter { it.isDirectory() }.map {
it.relativeTo(basedir)
it.relativeToOrSelf(basedir).invariantSeparatorsPath
}.toHashSet())
} finally {
basedir.deleteRecursively()
@@ -146,9 +142,7 @@ class FileTreeWalkTest {
@Test fun withDeleteTxtTopDown() {
val basedir = createTestFiles()
try {
val referenceNames =
listOf("", "1", "1/2", "1/3", "6", "8").map(
{ it -> it.separatorsToSystem() }).toHashSet()
val referenceNames = setOf("", "1", "1/2", "1/3", "6", "8")
val namesTopDown = HashSet<String>()
fun enter(file: File) {
assertTrue(file.isDirectory())
@@ -158,7 +152,7 @@ class FileTreeWalkTest {
}
}
for (file in basedir.walkTopDown().enter(::enter)) {
val name = file.relativeTo(basedir)
val name = file.relativeToOrSelf(basedir).invariantSeparatorsPath
assertFalse(namesTopDown.contains(name), "$name is visited twice")
namesTopDown.add(name)
}
@@ -171,9 +165,7 @@ class FileTreeWalkTest {
@Test fun withDeleteTxtBottomUp() {
val basedir = createTestFiles()
try {
val referenceNames =
listOf("", "1", "1/2", "1/3", "6", "8").map(
{ it -> it.separatorsToSystem() }).toHashSet()
val referenceNames = setOf("", "1", "1/2", "1/3", "6", "8")
val namesTopDown = HashSet<String>()
fun enter(file: File) {
assertTrue(file.isDirectory())
@@ -183,7 +175,7 @@ class FileTreeWalkTest {
}
}
for (file in basedir.walkBottomUp().enter(::enter)) {
val name = file.relativeTo(basedir)
val name = file.relativeToOrSelf(basedir).invariantSeparatorsPath
assertFalse(namesTopDown.contains(name), "$name is visited twice")
namesTopDown.add(name)
}
@@ -270,13 +262,13 @@ class FileTreeWalkTest {
@Test fun withVisitorAndDepth() {
val basedir = createTestFiles()
try {
val files = HashSet<String>()
val dirs = HashSet<String>()
val files = HashSet<File>()
val dirs = HashSet<File>()
val failed = HashSet<String>()
val stack = ArrayList<File>()
fun beforeVisitDirectory(dir: File) {
stack.add(dir)
dirs.add(dir.relativeTo(basedir))
dirs.add(dir.relativeToOrSelf(basedir))
}
fun afterVisitDirectory(dir: File) {
@@ -286,7 +278,7 @@ class FileTreeWalkTest {
fun visitFile(file: File) {
assert(stack.last().listFiles().contains(file)) { file }
files.add(file.relativeTo(basedir))
files.add(file.relativeToOrSelf(basedir))
}
fun visitDirectoryFailed(dir: File, e: IOException) {
@@ -298,10 +290,10 @@ class FileTreeWalkTest {
fail(::visitDirectoryFailed).forEach { it -> if (!it.isDirectory()) visitFile(it) }
assert(stack.isEmpty())
val sep = File.separator
for (fileName in arrayOf("", "1", "1${sep}2", "1${sep}3", "6", "8")) {
for (fileName in arrayOf("", "1", "1/2", "1/3", "6", "8")) {
assert(dirs.contains(fileName)) { fileName }
}
for (fileName in arrayOf("1${sep}3${sep}4.txt", "1${sep}3${sep}4.txt", "7.txt", "8${sep}9.txt")) {
for (fileName in arrayOf("1/3/4.txt", "1/3/4.txt", "7.txt", "8/9.txt")) {
assert(files.contains(fileName)) { fileName }
}
@@ -311,9 +303,9 @@ class FileTreeWalkTest {
basedir.walkTopDown().enter(::beforeVisitDirectory).leave(::afterVisitDirectory).maxDepth(1).
forEach { it -> if (it != basedir) visitFile(it) }
assert(stack.isEmpty())
assert(dirs.size == 1 && dirs.contains("")) { dirs.size }
assert(dirs.size == 1 && dirs.contains(File(""))) { dirs.size }
for (file in arrayOf("1", "6", "7.txt", "8")) {
assert(files.contains(file)) { file }
assert(files.contains(File(file))) { file }
}
//restrict access
@@ -327,11 +319,11 @@ class FileTreeWalkTest {
assert(failed.size == 1 && failed.contains("1")) { failed.size }
assert(dirs.size == 4) { dirs.size }
for (dir in arrayOf("", "1", "6", "8")) {
assert(dirs.contains(dir)) { dir }
assert(dirs.contains(File(dir))) { dir }
}
assert(files.size == 2) { files.size }
for (file in arrayOf("7.txt", "8${sep}9.txt")) {
assert(files.contains(file)) { file }
for (file in arrayOf("7.txt", "8/9.txt")) {
assert(files.contains(File(file))) { file }
}
} finally {
File(basedir, "1").setReadable(true)
@@ -418,7 +410,7 @@ class FileTreeWalkTest {
@Test fun find() {
val basedir = createTestFiles()
try {
File(basedir, "8/4.txt".separatorsToSystem()).createNewFile()
File(basedir, "8/4.txt").createNewFile()
var count = 0
basedir.walkTopDown().takeWhile { it -> count == 0 }.forEach {
if (it.name == "4.txt") {
+72 -58
View File
@@ -75,7 +75,7 @@ class FilesTest {
val file1 = File("/foo/bar/baz")
val file2 = File("/foo/baa/ghoo")
assertEquals("../../bar/baz".separatorsToSystem(), file1.relativeTo(file2))
assertEquals("../../bar/baz", file1.relativeToFile(file2).invariantSeparatorsPath)
val file3 = File("/foo/bar")
@@ -91,10 +91,10 @@ class FilesTest {
val file5 = File("/foo/baran")
assertEquals("../bar".separatorsToSystem(), file3.relativeTo(file5))
assertEquals("../baran".separatorsToSystem(), file5.relativeTo(file3))
assertEquals("../bar".separatorsToSystem(), file4.relativeTo(file5))
assertEquals("../baran".separatorsToSystem(), file5.relativeTo(file4))
assertEquals("../bar", file3.relativeToFile(file5).invariantSeparatorsPath)
assertEquals("../baran", file5.relativeToFile(file3).invariantSeparatorsPath)
assertEquals("../bar", file4.relativeToFile(file5).invariantSeparatorsPath)
assertEquals("../baran", file5.relativeToFile(file4).invariantSeparatorsPath)
val file6 = File("C:\\Users\\Me")
val file7 = File("C:\\Users\\Me\\Documents")
@@ -109,8 +109,8 @@ class FilesTest {
val file8 = File("""\\my.host\home/user/documents/vip""")
val file9 = File("""\\my.host\home/other/images/nice""")
assertEquals("../../../user/documents/vip".separatorsToSystem(), file8.relativeTo(file9))
assertEquals("../../../other/images/nice".separatorsToSystem(), file9.relativeTo(file8))
assertEquals("../../../user/documents/vip", file8.relativeToFile(file9).invariantSeparatorsPath)
assertEquals("../../../other/images/nice", file9.relativeToFile(file8).invariantSeparatorsPath)
}
@test fun relativeToRelative() {
@@ -165,56 +165,66 @@ class FilesTest {
}
assertFailsRelativeTo(File("y"), File("../x"))
// This test operates correctly only at Windows PCs with C & D drives
val fileOnC = File("C:/dir1")
val fileOnD = File("D:/dir2")
assertFailsRelativeTo(fileOnC, fileOnD)
}
@test fun relativeTo() {
assertEquals("kotlin", File("src/kotlin".separatorsToSystem()).relativeTo(File("src")))
assertEquals("kotlin", File("src/kotlin").relativeTo(File("src")))
assertEquals("", File("dir").relativeTo(File("dir")))
assertEquals("..", File("dir").relativeTo(File("dir/subdir".separatorsToSystem())))
assertEquals("../../test".separatorsToSystem(), File("test").relativeTo(File("dir/dir".separatorsToSystem())))
// This test operates correctly only at Windows PCs with C & D drives
val file1 = File("C:/dir1".separatorsToSystem())
val file2 = File("D:/dir2".separatorsToSystem())
try {
file1.relativeTo(file2)
assert(false);
} catch (e: IllegalArgumentException) {
// It's the thing we should get here
} catch (e: IOException) {
// The device is not ready (D) ==> DO NOTHING
}
assertEquals("..", File("dir").relativeTo(File("dir/subdir")))
assertEquals(File("../../test"), File("test").relativeToFile(File("dir/dir")))
}
private fun checkFileElements(f: File, root: File?, elements: List<String>) {
var i = 0
private fun checkFilePathComponents(f: File, root: File, elements: List<String>) {
assertEquals(root, f.root)
for (elem in f.toComponents().segments) {
assertTrue(i < elements.size, i.toString())
assertEquals(elements[i++], elem.toString())
}
assertEquals(elements.size, i)
val components = f.toComponents()
assertEquals(root, components.root)
assertEquals(elements, components.segments.map { it.toString() })
}
@test fun fileIterator() {
checkFileElements(File("/foo/bar"), File("/"), listOf("foo", "bar"))
checkFileElements(File("\\foo\\bar"), File("\\".separatorsToSystem()), listOf("foo", "bar"))
checkFileElements(File("/foo/bar/gav"), File("/"), listOf("foo", "bar", "gav"))
checkFileElements(File("/foo/bar/gav/"), File("/"), listOf("foo", "bar", "gav"))
checkFileElements(File("bar/gav"), null, listOf("bar", "gav"))
checkFileElements(File("C:\\bar\\gav"), File("C:\\".separatorsToSystem()), listOf("bar", "gav"))
checkFileElements(File("C:/bar/gav"), File("C:/"), listOf("bar", "gav"))
checkFileElements(File("C:\\"), File("C:\\".separatorsToSystem()), listOf())
checkFileElements(File("C:/"), File("C:/"), listOf())
checkFileElements(File("C:"), File("C:"), listOf())
if (File.separatorChar == '\\') {
@test fun filePathComponents() {
checkFilePathComponents(File("/foo/bar"), File("/"), listOf("foo", "bar"))
checkFilePathComponents(File("/foo/bar/gav"), File("/"), listOf("foo", "bar", "gav"))
checkFilePathComponents(File("/foo/bar/gav/"), File("/"), listOf("foo", "bar", "gav"))
checkFilePathComponents(File("bar/gav"), File(""), listOf("bar", "gav"))
checkFilePathComponents(File("C:/bar/gav"), File("C:/"), listOf("bar", "gav"))
checkFilePathComponents(File("C:/"), File("C:/"), listOf())
checkFilePathComponents(File("C:"), File("C:"), listOf())
if (File.separator == "\\") {
// Check only in Windows
checkFileElements(File("\\\\host.ru\\home\\mike"), File("\\\\host.ru\\home"), listOf("mike"))
checkFileElements(File("//host.ru/home/mike"), File("//host.ru/home"), listOf("mike"))
checkFilePathComponents(File("\\\\host.ru\\home\\mike"), File("\\\\host.ru\\home"), listOf("mike"))
checkFilePathComponents(File("//host.ru/home/mike"), File("//host.ru/home"), listOf("mike"))
checkFilePathComponents(File("\\foo\\bar"), File("\\"), listOf("foo", "bar"))
checkFilePathComponents(File("C:\\bar\\gav"), File("C:\\"), listOf("bar", "gav"))
checkFilePathComponents(File("C:\\"), File("C:\\"), listOf())
}
checkFileElements(File(""), null, listOf())
checkFileElements(File("."), null, listOf("."))
checkFileElements(File(".."), null, listOf(".."))
checkFilePathComponents(File(""), File(""), listOf())
checkFilePathComponents(File("."), File(""), listOf("."))
checkFilePathComponents(File(".."), File(""), listOf(".."))
}
@test fun fileRoot() {
val rooted = File("/foo/bar")
assertTrue(rooted.isRooted)
assertEquals("/", rooted.root.invariantSeparatorsPath)
if (File.separator == "\\") {
val diskRooted = File("""C:\foo\bar""")
assertTrue(rooted.isRooted)
assertEquals("""C:\""", diskRooted.rootName)
val networkRooted = File("""\\network\share\""")
assertTrue(networkRooted.isRooted)
assertEquals("""\\network\share""", networkRooted.rootName)
}
val relative = File("foo/bar")
assertFalse(relative.isRooted)
assertEquals("", relative.rootName)
}
@test fun startsWith() {
@@ -254,9 +264,10 @@ class FilesTest {
assertEquals(File("/foo/bar/baaz"), File("/foo/bak/../bar/gav/../baaz").normalize())
assertEquals(File("../../bar"), File("../foo/../../bar").normalize())
// For Unix C:\windows is not correct so it's not the same as C:/windows
assertEquals(File("C:\\windows").separatorsToSystem(),
File("C:\\home\\..\\documents\\..\\windows").normalize().separatorsToSystem())
assertEquals(File("C:/windows"), File("C:/home/../documents/../windows").normalize())
if (File.separator == "\\") {
assertEquals(File("C:\\windows"), File("C:\\home\\..\\documents\\..\\windows").normalize())
assertEquals(File("C:/windows"), File("C:/home/../documents/../windows").normalize())
}
assertEquals(File("foo"), File("gav/bar/../../foo").normalize())
assertEquals(File("/../foo"), File("/bar/../../foo").normalize())
}
@@ -266,11 +277,12 @@ class FilesTest {
assertEquals(File("/foo/bar/gav"), File("/foo/bar/").resolve("gav"))
assertEquals(File("/gav"), File("/foo/bar").resolve("/gav"))
// For Unix C:\path is not correct so it's cannot be automatically converted
assertEquals(File("C:\\Users\\Me\\Documents\\important.doc").separatorsToSystem(),
File("C:\\Users\\Me").resolve("Documents\\important.doc").separatorsToSystem())
assertEquals(File("C:/Users/Me/Documents/important.doc"),
File("C:/Users/Me").resolve("Documents/important.doc"))
if (File.separator == "\\") {
assertEquals(File("C:\\Users\\Me\\Documents\\important.doc"),
File("C:\\Users\\Me").resolve("Documents\\important.doc"))
assertEquals(File("C:/Users/Me/Documents/important.doc"),
File("C:/Users/Me").resolve("Documents/important.doc"))
}
assertEquals(File(""), File("").resolve(""))
assertEquals(File("bar"), File("").resolve("bar"))
assertEquals(File("foo/bar"), File("foo").resolve("bar"))
@@ -285,10 +297,12 @@ class FilesTest {
assertEquals(File("/foo/gav"), File("/foo/bar/").resolveSibling("gav"))
assertEquals(File("/gav"), File("/foo/bar").resolveSibling("/gav"))
// For Unix C:\path is not correct so it's cannot be automatically converted
assertEquals(File("C:\\Users\\Me\\Documents\\important.doc").separatorsToSystem(),
File("C:\\Users\\Me\\profile.ini").resolveSibling("Documents\\important.doc").separatorsToSystem())
assertEquals(File("C:/Users/Me/Documents/important.doc"),
File("C:/Users/Me/profile.ini").resolveSibling("Documents/important.doc"))
if (File.separator == "\\") {
assertEquals(File("C:\\Users\\Me\\Documents\\important.doc"),
File("C:\\Users\\Me\\profile.ini").resolveSibling("Documents\\important.doc"))
assertEquals(File("C:/Users/Me/Documents/important.doc"),
File("C:/Users/Me/profile.ini").resolveSibling("Documents/important.doc"))
}
assertEquals(File("gav"), File("foo").resolveSibling("gav"))
assertEquals(File("../gav"), File("").resolveSibling("gav"))
}