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

Refactor DOT dump for Ets files #251

Merged
merged 22 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ jobs:
# Builds on other branches will only read existing entries from the cache.
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}

- name: Set up GraphViz
uses: ts-graphviz/setup-graphviz@v2

- name: Set up Node
uses: actions/setup-node@v4
with:
Expand Down
4 changes: 3 additions & 1 deletion buildSrc/src/main/kotlin/Tests.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.testing.Test
import java.util.*
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import java.util.StringTokenizer

object Tests {
val lifecycleTag = "lifecycle"
Expand All @@ -10,6 +11,7 @@ object Tests {
fun Test.setup(jacocoTestReport: TaskProvider<*>) {
testLogging {
events("passed", "skipped", "failed")
exceptionFormat = TestExceptionFormat.FULL
}
finalizedBy(jacocoTestReport) // report is always generated after tests run
val majorJavaVersion =
Expand Down
41 changes: 41 additions & 0 deletions jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/Dot.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2022 UnitTestBot contributors (utbot.org)
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.jacodb.ets.utils

import mu.KotlinLogging
import java.io.File
import kotlin.time.Duration.Companion.seconds

private val logger = KotlinLogging.logger {}

fun render(path: String, dump: (File) -> Unit) {
Lipen marked this conversation as resolved.
Show resolved Hide resolved
val dotFile = File(path)
dump(dotFile)
logger.info { "Generated DOT file: ${dotFile.absolutePath}" }
for (format in listOf("pdf")) {
val formatFile = dotFile.resolveSibling(dotFile.nameWithoutExtension + ".$format")
rudolf101 marked this conversation as resolved.
Show resolved Hide resolved
val cmd: List<String> = listOf(
"dot",
"-T$format",
"$dotFile",
"-o",
"$formatFile"
)
runProcess(cmd, 60.seconds)
logger.info { "Generated ${format.uppercase()} file: ${formatFile.absolutePath}" }
}
}
32 changes: 32 additions & 0 deletions jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/EtsFileDtoToDot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.jacodb.ets.dto.NopStmtDto
import org.jacodb.ets.dto.StmtDto
import org.jacodb.ets.dto.SwitchStmtDto
import java.io.BufferedWriter
import java.io.File
import java.nio.file.Path
import kotlin.io.path.writeText
Expand Down Expand Up @@ -182,6 +183,37 @@
return lines.joinToString("\n")
}

fun EtsFileDto.dumpHuimpleTo(output: BufferedWriter) {
rudolf101 marked this conversation as resolved.
Show resolved Hide resolved
output.writeln("EtsFileDto '${name}':")
classes.forEach { clazz ->
output.writeln("= CLASS '${clazz.signature}':")
output.writeln(" superClass = '${clazz.superClassName}'")
output.writeln(" typeParameters = ${clazz.typeParameters}")
output.writeln(" modifiers = ${clazz.modifiers}")
output.writeln(" fields: ${clazz.fields.size}")
clazz.fields.forEach { field ->
output.writeln(" - FIELD '${field.signature}'")
output.writeln(" typeParameters = ${field.typeParameters}")
output.writeln(" modifiers = ${field.modifiers}")
output.writeln(" isOptional = ${field.isOptional}")
output.writeln(" isDefinitelyAssigned = ${field.isDefinitelyAssigned}")
}
output.writeln(" methods: ${clazz.methods.size}")
clazz.methods.forEach { method ->
output.writeln(" - METHOD '${method.signature}':")
output.writeln(" locals = ${method.body.locals}")
output.writeln(" typeParameters = ${method.typeParameters}")
output.writeln(" blocks: ${method.body.cfg.blocks.size}")
method.body.cfg.blocks.forEach { block ->
output.writeln(" - BLOCK ${block.id} with ${block.stmts.size} statements:")
block.stmts.forEachIndexed { i, inst ->
output.writeln(" ${i + 1}. $inst")
rudolf101 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
}

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

View check run for this annotation

Codecov / codecov/patch

jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/EtsFileDtoToDot.kt#L187-L215

Added lines #L187 - L215 were not covered by tests

fun EtsFileDto.dumpDot(file: File) {
file.writeText(toDot())
}
Expand Down
27 changes: 27 additions & 0 deletions jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/EtsFileToDot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.jacodb.ets.model.EtsClass
import org.jacodb.ets.model.EtsFile
import org.jacodb.ets.model.EtsMethod
import java.io.BufferedWriter
import java.io.File
import java.nio.file.Path
import kotlin.io.path.writeText
Expand Down Expand Up @@ -146,6 +147,32 @@
return lines.joinToString("\n")
}

fun EtsFile.dumpHuimpleTo(output: BufferedWriter) {
Lipen marked this conversation as resolved.
Show resolved Hide resolved
output.writeln("EtsFile '${name}':")
classes.forEach { clazz ->
output.writeln("= CLASS '${clazz.signature}':")
output.writeln(" superClass = '${clazz.superClass}'")
output.writeln(" fields: ${clazz.fields.size}")
clazz.fields.forEach { field ->
output.writeln(" - FIELD '${field.signature}'")
}
output.writeln(" constructor = '${clazz.ctor.signature}'")
output.writeln(" stmts: ${clazz.ctor.cfg.stmts.size}")
clazz.ctor.cfg.stmts.forEachIndexed { i, stmt ->
output.writeln(" ${i + 1}. $stmt")
}
output.writeln(" methods: ${clazz.methods.size}")
clazz.methods.forEach { method ->
output.writeln(" - METHOD '${method.signature}':")
output.writeln(" locals = ${method.localsCount}")
output.writeln(" stmts: ${method.cfg.stmts.size}")
method.cfg.stmts.forEachIndexed { i, stmt ->
output.writeln(" ${i + 1}. $stmt")
}
}
}
}

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

View check run for this annotation

Codecov / codecov/patch

jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/EtsFileToDot.kt#L151-L174

Added lines #L151 - L174 were not covered by tests

fun EtsFile.dumpDot(file: File) {
file.writeText(toDot())
}
Expand Down
55 changes: 29 additions & 26 deletions jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,17 @@

package org.jacodb.ets.utils

import mu.KotlinLogging
import org.jacodb.ets.dto.EtsFileDto
import org.jacodb.ets.dto.convertToEtsFile
import org.jacodb.ets.model.EtsFile
import java.io.File
import java.io.FileNotFoundException
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.exists
import kotlin.io.path.inputStream
import kotlin.io.path.notExists
import kotlin.io.path.pathString

private val logger = KotlinLogging.logger {}
import kotlin.time.Duration.Companion.seconds

private const val ENV_VAR_ARK_ANALYZER_DIR = "ARKANALYZER_DIR"
private const val DEFAULT_ARK_ANALYZER_DIR = "arkanalyzer"
Expand All @@ -40,10 +37,10 @@
private const val ENV_VAR_NODE_EXECUTABLE = "NODE_EXECUTABLE"
private const val DEFAULT_NODE_EXECUTABLE = "node"

fun loadEtsFileAutoConvert(tsPath: String): EtsFile {
val arkAnalyzerDir = Paths.get(System.getenv(ENV_VAR_ARK_ANALYZER_DIR) ?: DEFAULT_ARK_ANALYZER_DIR)
fun generateEtsFileIR(tsPath: String): 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'. 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 '${Paths.get("").toAbsolutePath()}'.")
throw FileNotFoundException("ArkAnalyzer directory does not exist: '$arkAnalyzerDir'. 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()}'.")

Check warning on line 43 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#L43

Added line #L43 was not covered by tests
}

val scriptPath = System.getenv(ENV_VAR_SERIALIZE_SCRIPT_PATH) ?: DEFAULT_SERIALIZE_SCRIPT_PATH
Expand All @@ -60,26 +57,32 @@
tsPath,
output.pathString,
)
logger.info { "Running: '${cmd.joinToString(" ")}'" }
val process = ProcessBuilder(cmd).start()
val ok = process.waitFor(1, TimeUnit.MINUTES)

val stdout = process.inputStream.bufferedReader().readText().trim()
if (stdout.isNotBlank()) {
logger.info { "STDOUT:\n$stdout" }
}
val stderr = process.errorStream.bufferedReader().readText().trim()
if (stderr.isNotBlank()) {
logger.info { "STDERR:\n$stderr" }
}
runProcess(cmd, 60.seconds)
return output
}

if (!ok) {
logger.info { "Timeout!" }
process.destroy()
fun loadEtsFileAutoConvert(tsPath: String): EtsFile {
val irFilePath = generateEtsFileIR(tsPath)
irFilePath.inputStream().use { stream ->
val etsFileDto = EtsFileDto.loadFromJson(stream)
val etsFile = convertToEtsFile(etsFileDto)
return etsFile
}
}

output.inputStream().use { stream ->
fun loadEtsFileAutoConvertWithDot(tsPath: String, dotDir: String): EtsFile {
val irFilePath = generateEtsFileIR(tsPath)
irFilePath.inputStream().use { stream ->
val etsFileDto = EtsFileDto.loadFromJson(stream)
return convertToEtsFile(etsFileDto)
val etsFile = convertToEtsFile(etsFileDto)
val etsFileDtoDotFileName = "$dotDir/${tsPath.substringAfterLast("/")}".replace(".ts", "Dto.dot")
val etsFileDotFileName = "$dotDir/${tsPath.substringAfterLast("/")}".replace(".ts", ".dot")
render(etsFileDtoDotFileName) { file ->
etsFileDto.dumpDot(file)
}
render(etsFileDotFileName) { file ->
etsFile.dumpDot(file)
}
return etsFile
}
}
54 changes: 54 additions & 0 deletions jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/Utils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2022 UnitTestBot contributors (utbot.org)
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.jacodb.ets.utils

import mu.KotlinLogging
import java.io.BufferedWriter
import java.util.concurrent.TimeUnit
import kotlin.time.Duration

private val logger = KotlinLogging.logger {}

internal fun BufferedWriter.writeln(s: String) {
write(s)
newLine()
}

Check warning on line 29 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#L27-L29

Added lines #L27 - L29 were not covered by tests

internal fun runProcess(cmd: List<String>, timeout: Duration? = null) {

Check warning on line 31 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#L31

Added line #L31 was not covered by tests
logger.info { "Running: '${cmd.joinToString(" ")}'" }
val process = ProcessBuilder(cmd).start()
val ok = if (timeout == null) {
process.waitFor()
true

Check warning on line 36 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#L35-L36

Added lines #L35 - L36 were not covered by tests
} else {
process.waitFor(timeout.inWholeNanoseconds, TimeUnit.NANOSECONDS)
}

val stdout = process.inputStream.bufferedReader().readText().trim()
if (stdout.isNotBlank()) {
logger.info { "STDOUT:\n$stdout" }
}
val stderr = process.errorStream.bufferedReader().readText().trim()
if (stderr.isNotBlank()) {
logger.info { "STDERR:\n$stderr" }

Check warning on line 47 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#L47

Added line #L47 was not covered by tests
}

if (!ok) {
logger.info { "Timeout!" }
process.destroy()

Check warning on line 52 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#L51-L52

Added lines #L51 - L52 were not covered by tests
}
}
14 changes: 12 additions & 2 deletions jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsFromJsonTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import org.jacodb.ets.model.EtsClassSignature
import org.jacodb.ets.model.EtsMethodSignature
import org.jacodb.ets.test.utils.loadEtsFileDtoFromResource
import org.jacodb.ets.utils.loadEtsFileAutoConvert
import org.jacodb.ets.utils.loadEtsFileAutoConvertWithDot
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test

Expand Down Expand Up @@ -72,13 +73,22 @@ class EtsFromJsonTest {

@Test
fun testLoadEtsFileAutoConvert() {
val path = "source/example.ts"
val res = this::class.java.getResource("/$path")
val path = "/source/example.ts"
val res = this::class.java.getResource(path)
?: error("Resource not found: $path")
val etsFile = loadEtsFileAutoConvert(res.path)
println("etsFile = $etsFile")
}

@Test
fun testLoadEtsFileAutoConvertWithDot() {
val path = "/source/example.ts"
val res = this::class.java.getResource(path)
?: error("Resource not found: $path")
val etsFile = loadEtsFileAutoConvertWithDot(res.path, res.path.substringBeforeLast("/"))
rudolf101 marked this conversation as resolved.
Show resolved Hide resolved
println("etsFile = $etsFile")
}

@Test
fun testLoadValueFromJson() {
val jsonString = """
Expand Down
Loading
Loading