Skip to content

Commit

Permalink
Generate local test resources via Gradle task (#258)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lipen authored Aug 16, 2024
1 parent 27245da commit 29d5df0
Show file tree
Hide file tree
Showing 89 changed files with 109 additions and 50,156 deletions.
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 {
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 org.jacodb.ets.model.EtsFile
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 @@ fun generateEtsFileIR(tsPath: Path): Path {
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()}'. " +
"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 @@ package org.jacodb.ets.utils
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 @@ internal fun runProcess(cmd: List<String>, timeout: Duration? = null) {
}
}

/**
* 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))
}

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

0 comments on commit 29d5df0

Please sign in to comment.