Fix missing resources in native pkldoc, and disable test mode (#1175)

This fixes two issues:

1. Test mode is enabled in pkldoc without the ability to turn it off
2. Native pkldoc is missing required resources

This also adds tests for both `jpkldoc` and `pkldoc`.
This commit is contained in:
Daniel Chao
2025-08-21 06:44:13 -07:00
committed by GitHub
parent ae5f02b285
commit d9db939bdc
13 changed files with 577 additions and 186 deletions

View File

@@ -69,6 +69,9 @@ class DocCommand : BaseCommand(name = "pkldoc", helpLink = helpLink) {
.single()
.flag(default = false)
private val isTestMode by
option(names = arrayOf("--test-mode"), help = "Internal test mode", hidden = true).flag()
private val projectOptions by ProjectOptions()
override val helpString: String = "Generate HTML documentation from Pkl modules and packages."
@@ -78,7 +81,7 @@ class DocCommand : BaseCommand(name = "pkldoc", helpLink = helpLink) {
CliDocGeneratorOptions(
baseOptions.baseOptions(modules, projectOptions),
outputDir,
true,
isTestMode,
noSymlinks,
)
CliDocGenerator(options).run()

View File

@@ -18,11 +18,9 @@ package org.pkl.doc
import com.google.common.jimfs.Configuration
import com.google.common.jimfs.Jimfs
import java.net.URI
import java.nio.file.FileSystem
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.*
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
@@ -31,83 +29,20 @@ import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.cli.CliException
import org.pkl.commons.readString
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.test.PackageServer
import org.pkl.commons.test.listFilesRecursively
import org.pkl.commons.toPath
import org.pkl.commons.walk
import org.pkl.core.Version
import org.pkl.core.util.IoUtils
import org.pkl.doc.DocGenerator.Companion.current
class CliDocGeneratorTest {
companion object {
private val tempFileSystem: FileSystem by lazy { Jimfs.newFileSystem(Configuration.unix()) }
private val tempFileSystem by lazy { Jimfs.newFileSystem(Configuration.unix()) }
private val tmpOutputDir by lazy {
private val tmpOutputDir: Path by lazy {
tempFileSystem.getPath("/work/output").apply { createDirectories() }
}
private val projectDir = FileTestUtils.rootProjectDir.resolve("pkl-doc")
private val inputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/input").apply { assert(exists()) }
}
private val docsiteModule: URI by lazy {
inputDir.resolve("docsite-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1PackageModule: URI by lazy {
inputDir.resolve("com.package1/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
private val package2PackageModule: URI by lazy {
inputDir.resolve("com.package2/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1InputModules: List<URI> by lazy {
inputDir
.resolve("com.package1")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
private val package2InputModules: List<URI> by lazy {
inputDir
.resolve("com.package2")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
private val expectedOutputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/output").createDirectories()
}
private val expectedOutputFiles: List<Path> by lazy { expectedOutputDir.listFilesRecursively() }
private val actualOutputDir: Path by lazy { tempFileSystem.getPath("/work/DocGeneratorTest") }
private val actualOutputFiles: List<Path> by lazy { actualOutputDir.listFilesRecursively() }
private val expectedRelativeOutputFiles: List<String> by lazy {
expectedOutputFiles.map { path ->
IoUtils.toNormalizedPathString(expectedOutputDir.relativize(path)).let { str ->
// Git will by default clone symlinks as shortcuts on Windows, and shortcuts have a
// `.lnk` extension.
if (IoUtils.isWindows() && str.endsWith(".lnk")) str.dropLast(4) else str
}
}
}
private val actualRelativeOutputFiles: List<String> by lazy {
actualOutputFiles.map { IoUtils.toNormalizedPathString(actualOutputDir.relativize(it)) }
}
private val binaryFileExtensions = setOf("woff2", "png", "svg")
private val helper = DocGeneratorTestHelper()
private fun runDocGenerator(outputDir: Path, cacheDir: Path?, noSymlinks: Boolean = false) {
CliDocGenerator(
@@ -115,14 +50,14 @@ class CliDocGeneratorTest {
CliBaseOptions(
sourceModules =
listOf(
docsiteModule,
package1PackageModule,
package2PackageModule,
helper.docsiteModule,
helper.package1PackageModule,
helper.package2PackageModule,
URI("package://localhost:0/birds@0.5.0"),
URI("package://localhost:0/fruit@1.1.0"),
URI("package://localhost:0/unlisted@1.0.0"),
URI("package://localhost:0/deprecated@1.0.0"),
) + package1InputModules + package2InputModules,
) + helper.package1InputModules + helper.package2InputModules,
moduleCacheDir = cacheDir,
),
outputDir = outputDir,
@@ -135,19 +70,7 @@ class CliDocGeneratorTest {
@JvmStatic
private fun generateDocs(): List<String> {
val cacheDir = Files.createTempDirectory("cli-doc-generator-test-cache")
PackageServer.populateCacheDir(cacheDir)
runDocGenerator(actualOutputDir, cacheDir)
val missingFiles = expectedRelativeOutputFiles - actualRelativeOutputFiles.toSet()
if (missingFiles.isNotEmpty()) {
Assertions.fail<Unit>(
"The following expected files were not actually generated:\n" +
missingFiles.joinToString("\n")
)
}
return actualRelativeOutputFiles
return helper.generateDocs()
}
}
@@ -158,6 +81,7 @@ class CliDocGeneratorTest {
createParentDirectories()
createFile()
}
val descriptor2 =
tempFileSystem.getPath("/work/dir2/docsite-info.pkl").apply {
createParentDirectories()
@@ -220,49 +144,20 @@ class CliDocGeneratorTest {
@ParameterizedTest
@MethodSource("generateDocs")
fun test(relativeFilePath: String) {
val actualFile = actualOutputDir.resolve(relativeFilePath)
assertThat(actualFile)
.withFailMessage("Test bug: $actualFile should exist but does not.")
.exists()
// symlinks on Git and Windows is rather finnicky; they create shortcuts by default unless
// a core Git option is set. Also, by default, symlinks require administrator privileges to run.
// We'll just test that the symlink got created but skip verifying that it points to the right
// place.
if (actualFile.isSymbolicLink() && IoUtils.isWindows()) return
val expectedFile = expectedOutputDir.resolve(relativeFilePath)
if (expectedFile.exists()) {
when {
expectedFile.isSymbolicLink() -> {
assertThat(actualFile).isSymbolicLink
assertThat(expectedFile.readSymbolicLink().toString().toPath())
.isEqualTo(actualFile.readSymbolicLink().toString().toPath())
}
expectedFile.extension in binaryFileExtensions ->
assertThat(actualFile.readBytes()).isEqualTo(expectedFile.readBytes())
else -> assertThat(actualFile.readString()).isEqualTo(expectedFile.readString())
}
} else {
expectedFile.createParentDirectories()
if (actualFile.isSymbolicLink()) {
// needs special handling because `copyTo` can't copy symlinks between file systems
val linkTarget = actualFile.readSymbolicLink()
assertThat(linkTarget).isRelative
Files.createSymbolicLink(expectedFile, linkTarget.toString().toPath())
} else {
actualFile.copyTo(expectedFile)
}
Assertions.fail("Created missing expected file `$relativeFilePath`.")
}
DocTestUtils.testExpectedFile(
helper.expectedOutputDir,
helper.actualOutputDir,
relativeFilePath,
)
}
@Test
fun `creates a symlink called current by default`(@TempDir tempDir: Path) {
PackageServer.populateCacheDir(tempDir)
runDocGenerator(actualOutputDir, tempDir)
runDocGenerator(helper.actualOutputDir, tempDir)
val expectedSymlink = actualOutputDir.resolve("com.package1/current")
val expectedDestination = actualOutputDir.resolve("com.package1/1.2.3")
val expectedSymlink = helper.actualOutputDir.resolve("com.package1/current")
val expectedDestination = helper.actualOutputDir.resolve("com.package1/1.2.3")
assertThat(expectedSymlink).isSymbolicLink().matches {
Files.isSameFile(it, expectedDestination)
@@ -274,10 +169,10 @@ class CliDocGeneratorTest {
@TempDir tempDir: Path
) {
PackageServer.populateCacheDir(tempDir)
runDocGenerator(actualOutputDir, tempDir, noSymlinks = true)
runDocGenerator(helper.actualOutputDir, tempDir, noSymlinks = true)
val currentDirectory = actualOutputDir.resolve("com.package1/current")
val sourceDirectory = actualOutputDir.resolve("com.package1/1.2.3")
val currentDirectory = helper.actualOutputDir.resolve("com.package1/current")
val sourceDirectory = helper.actualOutputDir.resolve("com.package1/1.2.3")
assertThat(currentDirectory).isDirectory()
assertThat(currentDirectory.isSymbolicLink()).isFalse()

View File

@@ -0,0 +1,181 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.net.URI
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.exists
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.fail
import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.test.PackageServer
import org.pkl.commons.test.listFilesRecursively
import org.pkl.core.util.IoUtils
class DocGeneratorTestHelper {
internal val tempDir by lazy { Files.createTempDirectory("ExecutableCliDocGeneratorTest") }
internal val projectDir = FileTestUtils.rootProjectDir.resolve("pkl-doc")
internal val inputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/input").apply { assert(exists()) }
}
internal val docsiteModule: URI by lazy {
inputDir.resolve("docsite-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1PackageModule: URI by lazy {
inputDir.resolve("com.package1/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package2PackageModule: URI by lazy {
inputDir.resolve("com.package2/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1InputModules: List<URI> by lazy {
inputDir
.resolve("com.package1")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
internal val package2InputModules: List<URI> by lazy {
inputDir
.resolve("com.package2")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
internal val expectedOutputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/output").createDirectories()
}
internal val expectedOutputFiles: List<Path> by lazy { expectedOutputDir.listFilesRecursively() }
internal val actualOutputDir: Path by lazy {
tempDir.resolve("work/DocGeneratorTest").createDirectories()
}
internal val actualOutputFiles: List<Path> by lazy { actualOutputDir.listFilesRecursively() }
internal val cacheDir: Path by lazy { tempDir.resolve("cache") }
internal val sourceModules =
listOf(
docsiteModule,
package1PackageModule,
package2PackageModule,
URI("package://localhost:0/birds@0.5.0"),
URI("package://localhost:0/fruit@1.1.0"),
URI("package://localhost:0/unlisted@1.0.0"),
URI("package://localhost:0/deprecated@1.0.0"),
) + package1InputModules + package2InputModules
internal val expectedRelativeOutputFiles: List<String> by lazy {
expectedOutputFiles.map { path ->
IoUtils.toNormalizedPathString(expectedOutputDir.relativize(path)).let { str ->
// Git will by default clone symlinks as shortcuts on Windows, and shortcuts have a
// `.lnk` extension.
if (IoUtils.isWindows() && str.endsWith(".lnk")) str.dropLast(4) else str
}
}
}
internal val actualRelativeOutputFiles: List<String> by lazy {
actualOutputFiles.map { IoUtils.toNormalizedPathString(actualOutputDir.relativize(it)) }
}
fun runPklDocCli(executable: Path, options: CliDocGeneratorOptions) {
val command = buildList {
add(executable.toString())
add("--output-dir")
add(options.normalizedOutputDir.toString())
add("--cache-dir")
add(options.base.normalizedModuleCacheDir.toString())
add("--test-mode")
addAll(sourceModules.map { it.toString() })
}
val process =
with(ProcessBuilder(command)) {
redirectErrorStream(true)
start()
}
try {
val out = process.inputStream.reader().readText()
val exitCode = process.waitFor()
if (exitCode != 0) {
fail(
"""
Process exited with $exitCode.
Output:
"""
.trimIndent() + out
)
}
} finally {
process.destroy()
}
}
private fun generateDocsWith(doGenerate: (CliDocGeneratorOptions) -> Unit): List<String> {
PackageServer.populateCacheDir(cacheDir)
val options =
CliDocGeneratorOptions(
CliBaseOptions(
sourceModules =
listOf(
docsiteModule,
package1PackageModule,
package2PackageModule,
URI("package://localhost:0/birds@0.5.0"),
URI("package://localhost:0/fruit@1.1.0"),
URI("package://localhost:0/unlisted@1.0.0"),
URI("package://localhost:0/deprecated@1.0.0"),
) + package1InputModules + package2InputModules,
moduleCacheDir = cacheDir,
),
outputDir = actualOutputDir,
isTestMode = true,
noSymlinks = false,
)
doGenerate(options)
val missingFiles = expectedRelativeOutputFiles - actualRelativeOutputFiles.toSet()
if (missingFiles.isNotEmpty()) {
Assertions.fail<Unit>(
"The following expected files were not actually generated:\n" +
missingFiles.joinToString("\n")
)
}
return actualRelativeOutputFiles
}
fun generateDocsWithCli(executable: Path): List<String> {
return generateDocsWith { runPklDocCli(executable, it) }
}
fun generateDocs(): List<String> {
return generateDocsWith { CliDocGenerator(it).run() }
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.copyTo
import kotlin.io.path.createParentDirectories
import kotlin.io.path.exists
import kotlin.io.path.extension
import kotlin.io.path.isSymbolicLink
import kotlin.io.path.readBytes
import kotlin.io.path.readSymbolicLink
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.pkl.commons.readString
import org.pkl.commons.toPath
import org.pkl.core.util.IoUtils
object DocTestUtils {
private val binaryFileExtensions = setOf("woff2", "png", "svg")
fun testExpectedFile(expectedOutputDir: Path, actualOutputDir: Path, relativeFilePath: String) {
val actualFile = actualOutputDir.resolve(relativeFilePath)
assertThat(actualFile)
.withFailMessage("Test bug: $actualFile should exist but does not.")
.exists()
// symlinks on Git and Windows is rather finnicky; they create shortcuts by default unless
// a core Git option is set. Also, by default, symlinks require administrator privileges to run.
// We'll just test that the symlink got created but skip verifying that it points to the right
// place.
if (actualFile.isSymbolicLink() && IoUtils.isWindows()) return
val expectedFile = expectedOutputDir.resolve(relativeFilePath)
if (expectedFile.exists()) {
when {
expectedFile.isSymbolicLink() -> {
assertThat(actualFile).isSymbolicLink
assertThat(expectedFile.readSymbolicLink().toString().toPath())
.isEqualTo(actualFile.readSymbolicLink().toString().toPath())
}
expectedFile.extension in binaryFileExtensions ->
assertThat(actualFile.readBytes()).isEqualTo(expectedFile.readBytes())
else -> assertThat(actualFile.readString()).isEqualTo(expectedFile.readString())
}
} else {
expectedFile.createParentDirectories()
if (actualFile.isSymbolicLink()) {
// needs special handling because `copyTo` can't copy symlinks between file systems
val linkTarget = actualFile.readSymbolicLink()
assertThat(linkTarget).isRelative
Files.createSymbolicLink(expectedFile, linkTarget.toString().toPath())
} else {
actualFile.copyTo(expectedFile)
}
Assertions.fail("Created missing expected file `$relativeFilePath`.")
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import org.junit.jupiter.api.condition.DisabledIfSystemProperty
import org.junit.jupiter.api.condition.EnabledIfSystemProperty
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.pkl.commons.test.Executables
// need both annotations for this to work (see https://stackoverflow.com/a/63252081)
@EnabledIfSystemProperty(named = "org.pkl.doc.JavaExecutableTest", matches = "true")
@DisabledIfSystemProperty(named = "org.pkl.doc.JavaExecutableTest", matches = "(?!true)")
class JavaExecutableTest {
companion object {
val helper = DocGeneratorTestHelper()
@JvmStatic
private fun generateDocs(): List<String> =
helper.generateDocsWithCli(Executables.pkldoc.javaExecutable)
}
@ParameterizedTest()
@MethodSource("generateDocs")
fun test(relativePath: String) {
DocTestUtils.testExpectedFile(helper.expectedOutputDir, helper.actualOutputDir, relativePath)
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import org.junit.jupiter.api.condition.DisabledIfSystemProperty
import org.junit.jupiter.api.condition.EnabledIfSystemProperty
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.pkl.commons.test.Executables
// need both annotations for this to work (see https://stackoverflow.com/a/63252081)
@EnabledIfSystemProperty(named = "org.pkl.doc.NativeExecutableTest", matches = "true")
@DisabledIfSystemProperty(named = "org.pkl.doc.NativeExecutableTest", matches = "(?!true)")
class NativeExecutableTest {
companion object {
val helper = DocGeneratorTestHelper()
@JvmStatic
private fun generateDocs(): List<String> {
return helper.generateDocsWithCli(Executables.pkldoc.firstExistingNative)
}
}
@ParameterizedTest()
@MethodSource("generateDocs")
fun test(relativePath: String) {
DocTestUtils.testExpectedFile(helper.expectedOutputDir, helper.actualOutputDir, relativePath)
}
}

View File

@@ -26,17 +26,17 @@ import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Test
import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.readString
import org.pkl.doc.CliDocGeneratorTest.Companion.package1InputModules
import org.pkl.doc.CliDocGeneratorTest.Companion.package1PackageModule
class SearchTest {
companion object {
private val tempFileSystem = lazy { Jimfs.newFileSystem(Configuration.unix()) }
private val helper = DocGeneratorTestHelper()
private val jsContext = lazy {
// reuse CliDocGeneratorTest's input files (src/test/files/DocGeneratorTest/input)
val packageModule: URI = package1PackageModule
val inputModules: List<URI> = package1InputModules
val packageModule: URI = helper.package1PackageModule
val inputModules: List<URI> = helper.package1InputModules
val pkldocDir = tempFileSystem.value.rootDirectories.first()

View File

@@ -0,0 +1,93 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import com.google.common.jimfs.Configuration
import com.google.common.jimfs.Jimfs
import java.net.URI
import java.nio.file.FileSystem
import java.nio.file.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.exists
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.test.listFilesRecursively
import org.pkl.core.util.IoUtils
class TestUtils {
val tempFileSystem: FileSystem by lazy { Jimfs.newFileSystem(Configuration.unix()) }
val tmpOutputDir by lazy { tempFileSystem.getPath("/work/output").apply { createDirectories() } }
val projectDir = FileTestUtils.rootProjectDir.resolve("pkl-doc")
val inputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/input").apply { assert(exists()) }
}
val docsiteModule: URI by lazy {
inputDir.resolve("docsite-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1PackageModule: URI by lazy {
inputDir.resolve("com.package1/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
val package2PackageModule: URI by lazy {
inputDir.resolve("com.package2/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1InputModules: List<URI> by lazy {
inputDir
.resolve("com.package1")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
val package2InputModules: List<URI> by lazy {
inputDir
.resolve("com.package2")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
val expectedOutputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/output").createDirectories()
}
val expectedOutputFiles: List<Path> by lazy { expectedOutputDir.listFilesRecursively() }
val actualOutputDir: Path by lazy { tempFileSystem.getPath("/work/DocGeneratorTest") }
val actualOutputFiles: List<Path> by lazy { actualOutputDir.listFilesRecursively() }
val expectedRelativeOutputFiles: List<String> by lazy {
expectedOutputFiles.map { path ->
IoUtils.toNormalizedPathString(expectedOutputDir.relativize(path)).let { str ->
// Git will by default clone symlinks as shortcuts on Windows, and shortcuts have a
// `.lnk` extension.
if (IoUtils.isWindows() && str.endsWith(".lnk")) str.dropLast(4) else str
}
}
}
val actualRelativeOutputFiles: List<String> by lazy {
actualOutputFiles.map { IoUtils.toNormalizedPathString(actualOutputDir.relativize(it)) }
}
val binaryFileExtensions = setOf("woff2", "png", "svg")
}