[Native][tests] Naive implementation of glob expansion

This commit is contained in:
Dmitriy Dolovov
2021-11-26 17:50:26 +03:00
parent 6d52d21631
commit b051d2f67d
3 changed files with 176 additions and 4 deletions
@@ -0,0 +1,117 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.blackboxtest
import org.jetbrains.kotlin.konan.blackboxtest.support.util.expandGlob
import org.jetbrains.kotlin.konan.blackboxtest.support.util.sanitizedName
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.fail
import java.io.File
import kotlin.io.path.createTempDirectory
class GlobsExpansionTest {
private lateinit var testDir: File
@BeforeEach
fun setUp() {
testDir = createTempDirectory(GlobsExpansionTest::class.java.sanitizedName).toFile()
}
@Test
fun noGlobs() {
val fileName = "file.kt"
val dirNames = listOf(null, "foo", "foo/bar", "foo/bar/baz")
dirNames.forEach { dirName ->
val fullPattern = testDir.resolveNullable(dirName).resolve(fileName)
val expansionResult = expandGlob(fullPattern)
assertEquals(1, expansionResult.size)
assertEquals(fullPattern, expansionResult.first())
}
}
@Test
fun filePattern() {
val fileNames = listOf("one.kt", "two.kt", "three.kt", "four.java", "five.py")
val dirNames = listOf(null, "foo", "foo/bar", "foo/bar/baz")
val pattern = "*.kt"
dirNames.forEach { dirName ->
val dir = createDirWithFiles(dirName, fileNames)
val fullPattern = dir.resolve(pattern)
val expansionResult = expandGlob(fullPattern)
val kotlinOnyFiles = findAllKotlinFiles(dirName)
assertEquals(kotlinOnyFiles.size, expansionResult.size)
assertEquals(kotlinOnyFiles, expansionResult.toSet())
}
}
@Test
fun dirPattern() {
val fileNames = listOf("one.kt", "two.kt", "three.kt", "four.java", "five.py")
val dirNames = listOf(null, "foo", "bar", "baz")
val pattern = "ba*/*.kt" // covers "bar" & "baz" dirs
dirNames.forEach { dirName -> createDirWithFiles(dirName, fileNames) }
val fullPattern = testDir.resolve(pattern)
val expansionResult = expandGlob(fullPattern)
val kotlinOnyFiles = findAllKotlinFiles("bar", "baz")
assertEquals(kotlinOnyFiles.size, expansionResult.size)
assertEquals(kotlinOnyFiles, expansionResult.toSet())
}
@Test
fun doubleStarPattern() {
val fileNames = listOf("one.kt", "two.kt", "three.kt", "four.java", "five.py")
val dirNames = listOf(null, "foo", "foo/bar", "foo/bar/baz")
val pattern = "foo/**.kt" // covers "foo" and all subdirectories
dirNames.forEach { dirName -> createDirWithFiles(dirName, fileNames) }
val fullPattern = testDir.resolve(pattern)
val expansionResult = expandGlob(fullPattern)
val kotlinOnyFiles = findAllKotlinFiles("foo", "foo/bar", "foo/bar/baz")
assertEquals(kotlinOnyFiles.size, expansionResult.size)
assertEquals(kotlinOnyFiles, expansionResult.toSet())
}
private fun createDirWithFiles(dirName: String?, fileNames: Collection<String>): File {
val dir = testDir.resolveNullable(dirName)
dir.mkdirs()
fileNames.forEach { fileName ->
dir.resolve(fileName).apply { createNewFile() }
}
return dir
}
private fun findAllKotlinFiles(vararg dirNames: String?): Set<File> = buildSet {
dirNames.forEach { dirName ->
val dir = testDir.resolveNullable(dirName)
assertTrue(dir.isDirectory) { "Directory does not exist or is not a directory: $dir ($dirName)." }
val files = dir.listFiles()?.takeIf { it.isNotEmpty() }
?: fail { "Unexpectedly empty directory: $dir ($dirName)." }
files.mapNotNullTo(this) { if (it.isFile && it.extension == "kt") it else null }
}
}
companion object {
private fun File.resolveNullable(nullable: String?): File = if (nullable != null) resolve(nullable) else this
}
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.blackboxtest.support.util
import java.io.File
import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes
import kotlin.io.path.name
/**
* Naive sub-optimal implementation of glob expansion.
*/
internal fun expandGlobTo(unexpendedPath: File, output: MutableCollection<File>) {
val normalizedUnexpandedPath = Paths.get(unexpendedPath.path).toAbsolutePath().normalize()
val paths = generateSequence(normalizedUnexpandedPath) { it.parent }.toMutableList().apply { reverse() }
for (index in 1 until paths.size) {
val path = paths[index]
val isGlob = '*' in path.name
if (isGlob) {
val basePath = paths[index - 1]
val pattern = basePath.relativize(normalizedUnexpandedPath).toString()
val matcher = FileSystems.getDefault().getPathMatcher("glob:$pattern")
Files.walkFileTree(basePath, object : SimpleFileVisitor<Path>() {
override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
if (matcher.matches(basePath.relativize(file))) output += file.toFile()
return FileVisitResult.CONTINUE
}
})
return
}
}
// No globs to expand.
output += normalizedUnexpandedPath.toFile()
}
internal fun expandGlob(unexpendedPath: File): Collection<File> = buildList { expandGlobTo(unexpendedPath, this) }
@@ -5,11 +5,21 @@
package org.jetbrains.kotlin.konan.blackboxtest.support.util
internal val Class<*>.sanitizedName: String
get() = name.map { if (it.isLetterOrDigit() || it == '_') it else '_' }.joinToString("")
internal val Class<*>.sanitizedName: String get() = sanitize(name)
internal fun getSanitizedFileName(fileName: String): String =
fileName.map { if (it.isLetterOrDigit() || it == '_' || it == '.') it else '_' }.joinToString("")
internal fun getSanitizedFileName(fileName: String): String = sanitize(fileName, allowDots = true)
private fun sanitize(s: String, allowDots: Boolean = false) = buildString {
s.forEach { ch ->
append(
when {
ch.isLetterOrDigit() || ch == '_' -> ch
allowDots && ch == '.' -> ch
else -> '_'
}
)
}
}
internal const val DEFAULT_FILE_NAME = "main.kt"