Skip to content

Commit de8fcea

Browse files
authored
Merge pull request #4 from Archinamon/feature/add_unsafe_ops
added unsafe getParent option; move separator value to common
2 parents f16cb02 + ae4262c commit de8fcea

File tree

7 files changed

+100
-27
lines changed

7 files changed

+100
-27
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
}
77

88
group = "me.archinamon"
9-
version = "1.3.1"
9+
version = "1.3.2"
1010

1111
val isRunningInIde: Boolean = System.getProperty("idea.active")
1212
?.toBoolean() == true

src/commonMain/kotlin/File.common.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ expect class File(pathname: String) {
2525
fun delete(): Boolean
2626
}
2727

28+
expect val filePathSeparator: Char
29+
2830
val File.nameWithoutExtension: String
2931
get() = getName().substringBeforeLast(".")
3032

@@ -43,6 +45,13 @@ fun File.deleteRecursively(): Boolean = walkBottomUp()
4345
(it.delete() || !it.exists()) && res
4446
}
4547

48+
fun File.getParentFileUnsafe(): File {
49+
return getParentFile()
50+
?: getAbsolutePath()
51+
.substringBeforeLast(filePathSeparator)
52+
.run(::File)
53+
}
54+
4655
fun File.validate() = run {
4756
print("Validating $nameWithoutExtension file...")
4857

src/commonTest/kotlin/FileTests.kt

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import kotlin.test.*
44

55
class FileTests {
66

7+
private val localSeparator = '/'
8+
79
@Test
810
fun testNonexistentRootFile() {
911
val testFile = File("testNonexistentRootFile.txt")
@@ -17,6 +19,18 @@ class FileTests {
1719
assertEquals("testNonexistentRootFile", testFile.nameWithoutExtension)
1820
}
1921

22+
@Test
23+
fun testExistentRootFile() {
24+
val testFile = File("testFileRoot/testExistentRootFile.txt")
25+
println(testFile.getAbsolutePath())
26+
27+
assertFalse(testFile.exists(), "file should not exist")
28+
assertFalse(testFile.getParentFile()?.exists() == true, "file should not have parent file")
29+
assertNotNull(testFile.getParentFileUnsafe(), "file should not have parent file")
30+
31+
assertEquals("testFileRoot", testFile.getParentFileUnsafe().getName(), "couldn't get parent file name")
32+
}
33+
2034
@Test
2135
fun testFileCreateAndDelete() {
2236
val testFolder = File("build/testNewDirectoryCreation")
@@ -70,4 +84,51 @@ class FileTests {
7084
assertEquals("gradle-wrapper.properties", listedFileNames[1])
7185
assertEquals("gradle-wrapper.properties", listedFiles[1].getName())
7286
}
87+
88+
@Test
89+
fun testFileCopyMethod() {
90+
val testFile = File("gradle/wrapper/gradle-wrapper.properties")
91+
val testDestFolder = File("build/testCopyFolder")
92+
val testDestFile = File("build/testCopyFolder/gradle-wrapper.properties")
93+
94+
assertTrue(testFile.exists(), "file have to exist")
95+
assertFalse(testDestFolder.exists(), "folder shouldn't be created yet")
96+
97+
testDestFolder.mkdirs()
98+
assertTrue(testDestFolder.exists(), "now folder have to exists")
99+
100+
assertFalse(testDestFile.exists(), "file should not exists yet")
101+
testFile.copyTo(testDestFile, overwrite = false)
102+
assertTrue(testDestFile.exists(), "file have to exist after coping")
103+
104+
assertTrue(testDestFile.delete(), "failed to cleanup test file")
105+
assertTrue(testDestFolder.delete(), "failed to cleanup directory")
106+
}
107+
108+
@Test
109+
fun testFileMoveMethod() {
110+
val testFolder = File("build/testMoveFolder")
111+
val testDestFolder = File("build/testMoveFolder2")
112+
val testFile = File("build/testMoveFolder/test_move_file.properties")
113+
val testDestFile = File("build/testMoveFolder2/test_move_file.properties")
114+
115+
assertFalse(testFile.exists(), "file have not to exist")
116+
assertFalse(testFolder.exists(), "folder shouldn't be created yet")
117+
assertFalse(testDestFolder.exists(), "folder shouldn't be created yet")
118+
119+
assertTrue(testFolder.mkdirs() && testFolder.exists(), "now folder1 have to exists")
120+
assertTrue(testDestFolder.mkdirs() && testDestFolder.exists(), "now folder2 have to exists")
121+
122+
assertTrue(testFile.createNewFile(), "file should be created")
123+
testFile.writeText("moving=true")
124+
125+
testFile.moveTo(testDestFile, overwrite = false)
126+
assertTrue(testDestFile.exists(), "file have to exist after coping")
127+
assertEquals("moving=true", testDestFile.readText(), "moved file should have the same content")
128+
assertFalse(testFile.exists(), "file should not exists on previous place after moving")
129+
130+
assertTrue(testFolder.delete(), "failed to cleanup test file")
131+
assertTrue(testDestFile.delete(), "failed to cleanup test file")
132+
assertTrue(testDestFolder.delete(), "failed to cleanup directory")
133+
}
73134
}

src/jsMain/kotlin/File.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ actual class File constructor(jsfile: JsFile) {
1515
actual fun getParent(): String? {
1616
return when {
1717
!exists() -> null
18-
"/" in innerFile.name -> innerFile.name
19-
.split("/")
18+
filePathSeparator in innerFile.name -> innerFile.name
19+
.split(filePathSeparator)
2020
.let { if (it.size > 1) it[it.lastIndex - 1] else it.last() }
2121
else -> innerFile.name
2222
}
@@ -79,6 +79,8 @@ actual class File constructor(jsfile: JsFile) {
7979
}
8080
}
8181

82+
actual val filePathSeparator by lazy { '/' }
83+
8284
actual val File.mimeType: String
8385
get() = innerFile.type
8486

src/jvmMain/kotlin/File.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import kotlin.io.writeBytes as kWriteBytes
88

99
actual typealias File = java.io.File
1010

11+
actual val filePathSeparator by lazy { File.separatorChar }
12+
1113
actual val File.mimeType: String
1214
get() = URLConnection.guessContentTypeFromName(name)
1315

src/mingwX64Main/kotlin/File.kt

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,21 @@ import platform.windows.*
77
private const val EPOCH_DIFF = 11644473600000
88

99

10-
actual class File actual constructor(
11-
private val pathname: String
12-
) {
13-
private val fileSeparator
14-
get() = if (Platform.osFamily == OsFamily.WINDOWS) "\\" else "/"
10+
actual class File actual constructor(pathname: String) {
11+
12+
private val pathname: String = pathname.replace('/', filePathSeparator)
1513

1614
actual fun getParent(): String? {
17-
return if (exists()) getAbsolutePath().substringBeforeLast(fileSeparator) else null
15+
return if (exists()) getAbsolutePath().substringBeforeLast(filePathSeparator) else null
1816
}
1917

2018
actual fun getParentFile(): File? {
2119
return getParent()?.run(::File)
2220
}
2321

2422
actual fun getName(): String {
25-
return if (fileSeparator in pathname) {
26-
pathname.split(fileSeparator).last(String::isNotBlank)
23+
return if (filePathSeparator in pathname) {
24+
pathname.split(filePathSeparator).last(String::isNotBlank)
2725
} else {
2826
pathname
2927
}
@@ -104,7 +102,7 @@ actual class File actual constructor(
104102
}
105103

106104
actual fun getAbsolutePath(): String {
107-
return if (pathname.startsWith(fileSeparator) || pathname.getOrNull(1) == ':') {
105+
return if (pathname.startsWith(filePathSeparator) || pathname.getOrNull(1) == ':') {
108106
pathname
109107
} else {
110108
memScoped {
@@ -119,7 +117,7 @@ actual class File actual constructor(
119117
retryBuf.toKString()
120118
} else {
121119
buf.toKString()
122-
} + fileSeparator + pathname
120+
} + filePathSeparator + pathname
123121
}
124122
}
125123
}
@@ -169,10 +167,10 @@ actual class File actual constructor(
169167
if (isFile()) return emptyArray()
170168

171169
val findData = alloc<WIN32_FIND_DATAA>()
172-
val searchPath = if (pathname.endsWith(fileSeparator)) {
170+
val searchPath = if (pathname.endsWith(filePathSeparator)) {
173171
pathname
174172
} else {
175-
"$pathname${fileSeparator}"
173+
"$pathname${filePathSeparator}"
176174
} + "*"
177175
val find = FindFirstFileA(searchPath, findData.ptr)
178176
if (find == INVALID_HANDLE_VALUE) {
@@ -197,8 +195,8 @@ actual class File actual constructor(
197195
actual fun listFiles(): Array<File> {
198196
if (isFile()) return emptyArray()
199197
val thisPath = getAbsolutePath().let { path ->
200-
if (!path.endsWith(fileSeparator)) {
201-
path + fileSeparator
198+
if (!path.endsWith(filePathSeparator)) {
199+
path + filePathSeparator
202200
} else path
203201
}
204202
return list()
@@ -268,6 +266,8 @@ actual class File actual constructor(
268266
}
269267
}
270268

269+
actual val filePathSeparator by lazy { if (Platform.osFamily == OsFamily.WINDOWS) '\\' else '/' }
270+
271271
actual val File.mimeType: String
272272
get() = ""
273273

src/posixMain/kotlin/File.kt

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,34 +45,31 @@ actual class File actual constructor(
4545
private val pathname: String
4646
) {
4747

48-
private val fileSeparator
49-
get() = if (Platform.osFamily == OsFamily.WINDOWS) "\\" else "/"
50-
5148
internal val modeRead = "r"
5249
private val modeAppend = "a"
5350
private val modeRewrite = "w"
5451

5552
actual fun getParent(): String? {
56-
return if (exists()) getAbsolutePath().substringBeforeLast(fileSeparator) else null
53+
return if (exists()) getAbsolutePath().substringBeforeLast(filePathSeparator) else null
5754
}
5855

5956
actual fun getParentFile(): File? {
6057
return getParent()?.run(::File)
6158
}
6259

6360
actual fun getName(): String {
64-
return if (fileSeparator in pathname) {
65-
pathname.split(fileSeparator).last(String::isNotBlank)
61+
return if (filePathSeparator in pathname) {
62+
pathname.split(filePathSeparator).last(String::isNotBlank)
6663
} else {
6764
pathname
6865
}
6966
}
7067

7168
actual fun getAbsolutePath(): String {
72-
return if (!pathname.startsWith(fileSeparator)) {
69+
return if (!pathname.startsWith(filePathSeparator)) {
7370
memScoped {
7471
getcwd(allocArray(FILENAME_MAX), FILENAME_MAX.convert())
75-
?.toKString() + fileSeparator + pathname
72+
?.toKString() + filePathSeparator + pathname
7673
}
7774
} else pathname
7875
}
@@ -156,8 +153,8 @@ actual class File actual constructor(
156153

157154
actual fun listFiles(): Array<File> {
158155
val thisPath = getAbsolutePath().let { path ->
159-
if (!path.endsWith(fileSeparator)) {
160-
path + fileSeparator
156+
if (!path.endsWith(filePathSeparator)) {
157+
path + filePathSeparator
161158
} else path
162159
}
163160
return list()
@@ -227,6 +224,8 @@ internal expect fun readdir(dir: CPointer<out CPointed>): CPointer<dirent>?
227224

228225
internal expect fun closedir(dir: CPointer<out CPointed>): Int
229226

227+
actual val filePathSeparator by lazy { if (Platform.osFamily == OsFamily.WINDOWS) '\\' else '/' }
228+
230229
//todo determine mimeType on file extension; see jdk mappings
231230
actual val File.mimeType: String
232231
get() = ""

0 commit comments

Comments
 (0)