Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate local test resources via Gradle task #258

Merged
merged 16 commits into from
Aug 16, 2024
3 changes: 3 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ jobs:
npm install
npm run build

- name: Generate test resources
run: ./gradlew :jacodb-ets:generateTestResources --scan

- name: Run ETS tests first
run: ./gradlew :jacodb-ets:test --scan

Expand Down
1 change: 0 additions & 1 deletion jacodb-ets/.gitignore

This file was deleted.

30 changes: 22 additions & 8 deletions jacodb-ets/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,46 @@ dependencies {

// Example usage:
// ```
// ARKANALYZER_DIR=~/dev/arkanalyzer ./gradlew generateTestResources
// export ARKANALYZER_DIR=~/dev/arkanalyzer
// ./gradlew generateTestResources
// ```
tasks.register("generateTestResources") {
group = "build"
description = "Generates test resources from TypeScript files using ArkAnalyzer."
doLast {
println("Generating test resources using ArkAnalyzer...")
val startTime = System.currentTimeMillis()

val envVarName = "ARKANALYZER_DIR"
val defaultArkAnalyzerDir = "../arkanalyzer"
val defaultArkAnalyzerDir = "arkanalyzer"

val arkAnalyzerDir = rootDir.resolve(System.getenv(envVarName) ?: run {
rudolf101 marked this conversation as resolved.
Show resolved Hide resolved
println("Please, set $envVarName environment variable. Using default value: '$defaultArkAnalyzerDir'")
defaultArkAnalyzerDir
})
if (!arkAnalyzerDir.exists()) {
throw FileNotFoundException("ArkAnalyzer directory does not exist: '$arkAnalyzerDir'. Did you forget to set the '$envVarName' environment variable?")
throw FileNotFoundException(
"ArkAnalyzer directory does not exist: '${arkAnalyzerDir.absolutePath}'. " +
"Did you forget to set the '$envVarName' environment variable? " +
"Current value is '${System.getenv(envVarName)}', " +
"current dir is '${File("").absolutePath}'."
)
}
println("Using ArkAnalyzer directory: '${arkAnalyzerDir.relativeTo(rootDir)}'")

val scriptSubPath = "src/save/serializeArkIR"
val script = arkAnalyzerDir.resolve("out").resolve("$scriptSubPath.js")
if (!script.exists()) {
throw FileNotFoundException("Script file not found: '$script'. Did you forget to execute 'npm run build' in the arkanalyzer project?")
throw FileNotFoundException(
"Script file not found: '$script'. " +
"Did you forget to execute 'npm run build' in the arkanalyzer project?"
)
}
println("Using script: '${script.relativeTo(arkAnalyzerDir)}'")

val resources = projectDir.resolve("src/test/resources")
val inputDir = resources.resolve("source")
val outputDir = resources.resolve("etsir/generated")
val inputDir = resources.resolve("samples/source")
val outputDir = resources.resolve("samples/etsir/ast")
println("Generating test resources in '${outputDir.relativeTo(projectDir)}'...")

val cmd: List<String> = listOf(
Expand All @@ -57,7 +71,7 @@ tasks.register("generateTestResources") {
outputDir.relativeTo(resources).path,
)
println("Running: '${cmd.joinToString(" ")}'")
val process = ProcessBuilder(cmd).directory(resources).start();
val process = ProcessBuilder(cmd).directory(resources).start()
val ok = process.waitFor(10, TimeUnit.MINUTES)

val stdout = process.inputStream.bufferedReader().readText().trim()
Expand All @@ -74,6 +88,6 @@ tasks.register("generateTestResources") {
process.destroy()
}

println("Done generating test resources!")
println("Done generating test resources in %.1fs".format((System.currentTimeMillis() - startTime) / 1000.0))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.io.FileNotFoundException
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.absolute
import kotlin.io.path.createTempDirectory
import kotlin.io.path.div
import kotlin.io.path.exists
Expand All @@ -44,7 +45,7 @@
val arkAnalyzerDir = Path(System.getenv(ENV_VAR_ARK_ANALYZER_DIR) ?: DEFAULT_ARK_ANALYZER_DIR)
if (!arkAnalyzerDir.exists()) {
throw FileNotFoundException(
"ArkAnalyzer directory does not exist: '$arkAnalyzerDir'. " +
"ArkAnalyzer directory does not exist: '${arkAnalyzerDir.absolute()}'. " +

Check warning on line 48 in jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt#L48

Added line #L48 was not covered by tests
"Did you forget to set the '$ENV_VAR_ARK_ANALYZER_DIR' environment variable? " +
"Current value is '${System.getenv(ENV_VAR_ARK_ANALYZER_DIR)}', " +
"current dir is '${Path("").toAbsolutePath()}'."
Expand Down
15 changes: 15 additions & 0 deletions jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import mu.KotlinLogging
import org.jacodb.ets.dto.EtsFileDto
import org.jacodb.ets.model.EtsFile
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import kotlin.time.Duration

Expand Down Expand Up @@ -49,6 +50,20 @@
}
}

/**
* Returns the path to the sibling of this path with the given name.
*
* Usage:
* ```
* val path = Path("foo/bar.jpeg")
* val sibling = path.resolveSibling { it.nameWithoutExtension + ".png" }
* println(sibling) // foo/bar.png
* ```
*/
internal fun Path.resolveSibling(name: (Path) -> String): Path {
return resolveSibling(name(this))

Check warning on line 64 in jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/Utils.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/Utils.kt#L64

Added line #L64 was not covered by tests
}

fun EtsFileDto.toText(): String {
val lines: MutableList<String> = mutableListOf()
lines += "EtsFileDto '${name}':"
Expand Down
10 changes: 6 additions & 4 deletions jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsFileTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,16 @@ private val logger = mu.KotlinLogging.logger {}
class EtsFileTest {

companion object {
private const val BASE = "/samples/etsir/ast"

private fun load(name: String): EtsFile {
return loadEtsFileFromResource("/$name.ts.json")
return loadEtsFileFromResource("$BASE/$name.ts.json")
}
}

@Test
fun printEtsInstructions() {
val etsFile = load("etsir/samples/classes/SimpleClass")
val etsFile = load("classes/SimpleClass")
etsFile.classes.forEach { cls ->
cls.methods.forEach { method ->
logger.info {
Expand All @@ -55,7 +57,7 @@ class EtsFileTest {

@Test
fun `test sample TypeMismatch`() {
val etsFile = load("etsir/samples/TypeMismatch")
val etsFile = load("TypeMismatch")
etsFile.classes.forEach { cls ->
cls.methods.forEach { method ->
when (method.name) {
Expand All @@ -73,7 +75,7 @@ class EtsFileTest {

@Test
fun `test sample FieldInitializers`() {
val etsFile = load("etsir/samples/classes/FieldInitializers")
val etsFile = load("classes/FieldInitializers")

val cls = etsFile.classes.single { it.name == "Foo" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class EtsFromJsonTest {

@Test
fun testLoadEtsFileFromJson() {
val path = "/etsir/samples/save/basic.ts.json"
val path = "/samples/etsir/ast/save/basic.ts.json"
val etsDto = loadEtsFileDtoFromResource("$path")
println("etsDto = $etsDto")
val ets = convertToEtsFile(etsDto)
Expand All @@ -71,7 +71,7 @@ class EtsFromJsonTest {

@Test
fun testLoadEtsFileAutoConvert() {
val path = "/source/example.ts"
val path = "/samples/source/example.ts"
val res = this::class.java.getResource(path)?.toURI()?.toPath()
?: error("Resource not found: $path")
val etsFile = loadEtsFileAutoConvert(res)
Expand All @@ -80,7 +80,7 @@ class EtsFromJsonTest {

@Test
fun testLoadEtsFileAutoConvertWithDot() {
val path = "/source/example.ts"
val path = "/samples/source/example.ts"
val res = this::class.java.getResource(path)?.toURI()?.toPath()
?: error("Resource not found: $path")
val etsFile = loadEtsFileAutoConvertWithDot(res)
Expand Down
4 changes: 2 additions & 2 deletions jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsIfds.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class EtsIfds {
}

private fun projectAvailable(): Boolean {
val resource = object {}::class.java.getResource("/samples/project1")?.toURI()
val resource = object {}::class.java.getResource("/samples/source/project1")?.toURI()
return resource != null && resource.toPath().exists()
}

Expand Down Expand Up @@ -162,7 +162,7 @@ class EtsIfds {
val getConfigForMethod: ForwardTaintFlowFunctions<EtsMethod, EtsStmt>.(EtsMethod) -> List<TaintConfigurationItem>? =
{ method ->
val rules = buildList {
if (method.name == "source") add(
if (method.name == "samples/source") add(
TaintMethodSource(
method = method,
condition = ConstantTrue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private val logger = mu.KotlinLogging.logger {}
class EtsTaintAnalysisTest {

companion object : EtsTraits {
private const val BASE_PATH = "/etsir/samples"
private const val BASE_PATH = "/samples/etsir/ast"

private const val DECOMPILED_PATH = "/decompiled"

Expand Down
59 changes: 27 additions & 32 deletions jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package org.jacodb.ets.test.utils

import org.jacodb.ets.dto.EtsFileDto
import org.jacodb.ets.dto.convertToEtsFile
import org.jacodb.ets.model.EtsFile
import org.jacodb.ets.utils.dumpDot
import org.jacodb.ets.utils.render
import org.jacodb.ets.utils.resolveSibling
import org.jacodb.ets.utils.toText
import java.nio.file.Path
import kotlin.io.path.ExperimentalPathApi
Expand Down Expand Up @@ -80,47 +82,40 @@ object DumpEtsFileToDot {
*/
@OptIn(ExperimentalPathApi::class)
object DumpEtsFilesToDot {
private const val ETSIR_BASE = "/etsir"
private const val ETSIR_DIR = "samples" // relative to BASE
private val DOT_DIR = Path("generated/dot")
private const val BASE = "/samples"
private const val ETSIR = "etsir/ast" // relative to BASE
private val DOT_DIR = Path("generated/samples/dot")

@JvmStatic
fun main(args: Array<String>) {
val resPath = "$ETSIR_BASE/$ETSIR_DIR"
val etsirDir = object {}::class.java.getResource(resPath)?.toURI()?.toPath()
?: error("Resource not found: '$resPath'")
logger.info { "baseDir = $etsirDir" }
val res = "$BASE/$ETSIR"
val etsirDir = object {}::class.java.getResource(res)?.toURI()?.toPath()
?: error("Resource not found: '$res'")
logger.info { "etsirDir = $etsirDir" }

etsirDir.walk()
.filter { it.name.endsWith(".json") }
.map { it.relativeTo(etsirDir) }
.forEach { path ->
val relative = path.relativeTo(etsirDir)

process(relative, ".dto") {
loadEtsFileDtoFromResource(it)
}
process(relative, "") {
loadEtsFileFromResource(it)
logger.info { "Processing: $path" }

val etsFileDto = loadEtsFileDtoFromResource("$BASE/$ETSIR/$path")
run {
val dotPath = DOT_DIR / path.resolveSibling {
it.nameWithoutExtension + ".dto.dot"
}
etsFileDto.dumpDot(dotPath)
render(DOT_DIR, dotPath.relativeTo(DOT_DIR))
}

logger.info { "Processed: $path" }
val etsFile = convertToEtsFile(etsFileDto)
run {
val dotPath = DOT_DIR / path.resolveSibling {
it.nameWithoutExtension + ".dot"
}
etsFile.dumpDot(dotPath)
render(DOT_DIR, dotPath.relativeTo(DOT_DIR))
}
}
}

private fun <T> process(
relative: Path,
suffix: String,
load: (String) -> T,
) {
val resourcePath = "$ETSIR_BASE/$ETSIR_DIR/$relative"
val relativeDot = (Path(ETSIR_DIR) / relative)
.resolveSibling("${relative.nameWithoutExtension}$suffix.dot")
val dotPath = DOT_DIR / relativeDot
when (val f = load(resourcePath)) {
is EtsFileDto -> f.dumpDot(dotPath)
is EtsFile -> f.dumpDot(dotPath)
else -> error("Unknown type: $f")
}
render(DOT_DIR, relativeDot)
}
}
3 changes: 3 additions & 0 deletions jacodb-ets/src/test/resources/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/samples/etsir/
/samples/abc/
/projects
Loading
Loading