mirror of
https://github.com/apple/pkl.git
synced 2026-04-24 17:28:37 +02:00
Add flag to turn power assertions on/off (#1419)
This commit is contained in:
@@ -454,6 +454,16 @@ output {
|
|||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
|
[[power-assertions-eval]]
|
||||||
|
.--power-assertions, --no-power-assertions
|
||||||
|
[%collapsible]
|
||||||
|
====
|
||||||
|
Default: enabled +
|
||||||
|
Enable or disable power assertions for detailed assertion failure messages.
|
||||||
|
When enabled, type constraint failures will show intermediate values in the assertion expression.
|
||||||
|
Use `--no-power-assertions` to disable this feature if you prefer simpler output or better performance.
|
||||||
|
====
|
||||||
|
|
||||||
This command also takes <<common-options, common options>>.
|
This command also takes <<common-options, common options>>.
|
||||||
|
|
||||||
[[command-server]]
|
[[command-server]]
|
||||||
@@ -524,6 +534,16 @@ Force generation of expected examples. +
|
|||||||
The old expected files will be deleted if present.
|
The old expected files will be deleted if present.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
[[power-assertions-test]]
|
||||||
|
.--power-assertions, --no-power-assertions
|
||||||
|
[%collapsible]
|
||||||
|
====
|
||||||
|
Default: enabled +
|
||||||
|
Enable or disable power assertions for detailed assertion failure messages.
|
||||||
|
When enabled, test failures will show intermediate values in the assertion expression, making it easier to understand why a test failed.
|
||||||
|
Use `--no-power-assertions` to disable this feature if you prefer simpler output.
|
||||||
|
====
|
||||||
|
|
||||||
This command also takes <<common-options, common options>>.
|
This command also takes <<common-options, common options>>.
|
||||||
|
|
||||||
[[command-repl]]
|
[[command-repl]]
|
||||||
|
|||||||
@@ -322,6 +322,16 @@ Default: `false` +
|
|||||||
Whether to ignore expected example files and generate them again.
|
Whether to ignore expected example files and generate them again.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
[[power-assertions-test]]
|
||||||
|
.powerAssertions: Property<Boolean>
|
||||||
|
[%collapsible]
|
||||||
|
====
|
||||||
|
Default: `true` (for test tasks) +
|
||||||
|
Example: `powerAssertions = false` +
|
||||||
|
Enable or disable power assertions for detailed assertion failure messages.
|
||||||
|
When enabled, test failures will show intermediate values in the assertion expression, making it easier to understand why a test failed.
|
||||||
|
====
|
||||||
|
|
||||||
Common properties:
|
Common properties:
|
||||||
|
|
||||||
include::../partials/gradle-modules-properties.adoc[]
|
include::../partials/gradle-modules-properties.adoc[]
|
||||||
|
|||||||
@@ -118,3 +118,13 @@ The left-hand side describes the source prefix, and the right-hand describes the
|
|||||||
This option is commonly used to enable package mirroring.
|
This option is commonly used to enable package mirroring.
|
||||||
The above example will rewrite URL `\https://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.0` to `\https://my.internal.mirror/pkl-k8s/k8s@1.0.0`.
|
The above example will rewrite URL `\https://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.0` to `\https://my.internal.mirror/pkl-k8s/k8s@1.0.0`.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
.powerAssertions: Property<Boolean>
|
||||||
|
[%collapsible]
|
||||||
|
====
|
||||||
|
Default: `false` (except for test tasks, which default to `true`) +
|
||||||
|
Example: `powerAssertions = true` +
|
||||||
|
Enable power assertions for detailed assertion failure messages.
|
||||||
|
When enabled, type constraint failures will show intermediate values in the assertion expression.
|
||||||
|
This option has a performance impact when constraint failures occur.
|
||||||
|
====
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -74,10 +74,23 @@ class EvalCommand : ModulesCommand(name = "eval", helpLink = helpLink) {
|
|||||||
private val testMode: Boolean by
|
private val testMode: Boolean by
|
||||||
option(names = arrayOf("--test-mode"), help = "Internal test mode", hidden = true).flag()
|
option(names = arrayOf("--test-mode"), help = "Internal test mode", hidden = true).flag()
|
||||||
|
|
||||||
|
private val powerAssertionsEnabled: Boolean by
|
||||||
|
option(
|
||||||
|
names = arrayOf("--power-assertions"),
|
||||||
|
help = "Enable power assertions for detailed assertion failure messages.",
|
||||||
|
)
|
||||||
|
.flag("--no-power-assertions", default = true, defaultForHelp = "enabled")
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val options =
|
val options =
|
||||||
CliEvaluatorOptions(
|
CliEvaluatorOptions(
|
||||||
base = baseOptions.baseOptions(modules, projectOptions, testMode = testMode),
|
base =
|
||||||
|
baseOptions.baseOptions(
|
||||||
|
modules,
|
||||||
|
projectOptions,
|
||||||
|
testMode = testMode,
|
||||||
|
powerAssertionsEnabled = powerAssertionsEnabled,
|
||||||
|
),
|
||||||
outputPath = outputPath,
|
outputPath = outputPath,
|
||||||
outputFormat = baseOptions.format,
|
outputFormat = baseOptions.format,
|
||||||
moduleOutputSeparator = moduleOutputSeparator,
|
moduleOutputSeparator = moduleOutputSeparator,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,6 +20,8 @@ import com.github.ajalt.clikt.parameters.arguments.argument
|
|||||||
import com.github.ajalt.clikt.parameters.arguments.convert
|
import com.github.ajalt.clikt.parameters.arguments.convert
|
||||||
import com.github.ajalt.clikt.parameters.arguments.multiple
|
import com.github.ajalt.clikt.parameters.arguments.multiple
|
||||||
import com.github.ajalt.clikt.parameters.groups.provideDelegate
|
import com.github.ajalt.clikt.parameters.groups.provideDelegate
|
||||||
|
import com.github.ajalt.clikt.parameters.options.flag
|
||||||
|
import com.github.ajalt.clikt.parameters.options.option
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import org.pkl.cli.CliTestRunner
|
import org.pkl.cli.CliTestRunner
|
||||||
import org.pkl.commons.cli.commands.BaseCommand
|
import org.pkl.commons.cli.commands.BaseCommand
|
||||||
@@ -43,9 +45,21 @@ class TestCommand : BaseCommand(name = "test", helpLink = helpLink) {
|
|||||||
|
|
||||||
private val testOptions by TestOptions()
|
private val testOptions by TestOptions()
|
||||||
|
|
||||||
|
private val powerAssertionsEnabled: Boolean by
|
||||||
|
option(
|
||||||
|
names = arrayOf("--power-assertions"),
|
||||||
|
help = "Enable power assertions for detailed assertion failure messages.",
|
||||||
|
)
|
||||||
|
.flag("--no-power-assertions", default = true, defaultForHelp = "enabled")
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
CliTestRunner(
|
CliTestRunner(
|
||||||
options = baseOptions.baseOptions(modules, projectOptions),
|
options =
|
||||||
|
baseOptions.baseOptions(
|
||||||
|
modules,
|
||||||
|
projectOptions,
|
||||||
|
powerAssertionsEnabled = powerAssertionsEnabled,
|
||||||
|
),
|
||||||
testOptions = testOptions.cliTestOptions,
|
testOptions = testOptions.cliTestOptions,
|
||||||
)
|
)
|
||||||
.run()
|
.run()
|
||||||
|
|||||||
@@ -52,7 +52,12 @@ class CliTestRunnerTest {
|
|||||||
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
||||||
val out = StringWriter()
|
val out = StringWriter()
|
||||||
val err = StringWriter()
|
val err = StringWriter()
|
||||||
val opts = CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
|
val opts =
|
||||||
|
CliBaseOptions(
|
||||||
|
sourceModules = listOf(input.toUri()),
|
||||||
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
|
)
|
||||||
val testOpts = CliTestOptions()
|
val testOpts = CliTestOptions()
|
||||||
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
||||||
runner.run()
|
runner.run()
|
||||||
@@ -89,7 +94,12 @@ class CliTestRunnerTest {
|
|||||||
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
||||||
val out = StringWriter()
|
val out = StringWriter()
|
||||||
val err = StringWriter()
|
val err = StringWriter()
|
||||||
val opts = CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
|
val opts =
|
||||||
|
CliBaseOptions(
|
||||||
|
sourceModules = listOf(input.toUri()),
|
||||||
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
|
)
|
||||||
val testOpts = CliTestOptions()
|
val testOpts = CliTestOptions()
|
||||||
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
||||||
assertThatCode { runner.run() }.hasMessage("Tests failed.")
|
assertThatCode { runner.run() }.hasMessage("Tests failed.")
|
||||||
@@ -131,7 +141,12 @@ class CliTestRunnerTest {
|
|||||||
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
||||||
val out = StringWriter()
|
val out = StringWriter()
|
||||||
val err = StringWriter()
|
val err = StringWriter()
|
||||||
val opts = CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
|
val opts =
|
||||||
|
CliBaseOptions(
|
||||||
|
sourceModules = listOf(input.toUri()),
|
||||||
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
|
)
|
||||||
val testOpts = CliTestOptions()
|
val testOpts = CliTestOptions()
|
||||||
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
||||||
assertThatCode { runner.run() }.hasMessage("Tests failed.")
|
assertThatCode { runner.run() }.hasMessage("Tests failed.")
|
||||||
@@ -173,7 +188,12 @@ class CliTestRunnerTest {
|
|||||||
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
||||||
val out = StringWriter()
|
val out = StringWriter()
|
||||||
val err = StringWriter()
|
val err = StringWriter()
|
||||||
val opts = CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
|
val opts =
|
||||||
|
CliBaseOptions(
|
||||||
|
sourceModules = listOf(input.toUri()),
|
||||||
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
|
)
|
||||||
val testOpts = CliTestOptions()
|
val testOpts = CliTestOptions()
|
||||||
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
||||||
assertThatCode { runner.run() }.hasMessage("Tests failed.")
|
assertThatCode { runner.run() }.hasMessage("Tests failed.")
|
||||||
@@ -229,7 +249,12 @@ class CliTestRunnerTest {
|
|||||||
)
|
)
|
||||||
val out = StringWriter()
|
val out = StringWriter()
|
||||||
val err = StringWriter()
|
val err = StringWriter()
|
||||||
val opts = CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
|
val opts =
|
||||||
|
CliBaseOptions(
|
||||||
|
sourceModules = listOf(input.toUri()),
|
||||||
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
|
)
|
||||||
val testOpts = CliTestOptions()
|
val testOpts = CliTestOptions()
|
||||||
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
||||||
assertThatCode { runner.run() }.hasMessage("Tests failed.")
|
assertThatCode { runner.run() }.hasMessage("Tests failed.")
|
||||||
@@ -275,7 +300,12 @@ class CliTestRunnerTest {
|
|||||||
.trimIndent()
|
.trimIndent()
|
||||||
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
||||||
val noopWriter = noopWriter()
|
val noopWriter = noopWriter()
|
||||||
val opts = CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
|
val opts =
|
||||||
|
CliBaseOptions(
|
||||||
|
sourceModules = listOf(input.toUri()),
|
||||||
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
|
)
|
||||||
val testOpts = CliTestOptions(junitDir = tempDir)
|
val testOpts = CliTestOptions(junitDir = tempDir)
|
||||||
val runner = CliTestRunner(opts, testOpts, noopWriter, noopWriter)
|
val runner = CliTestRunner(opts, testOpts, noopWriter, noopWriter)
|
||||||
assertThatCode { runner.run() }.hasMessageContaining("failed")
|
assertThatCode { runner.run() }.hasMessageContaining("failed")
|
||||||
@@ -320,7 +350,12 @@ class CliTestRunnerTest {
|
|||||||
.trimIndent()
|
.trimIndent()
|
||||||
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
||||||
val noopWriter = noopWriter()
|
val noopWriter = noopWriter()
|
||||||
val opts = CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
|
val opts =
|
||||||
|
CliBaseOptions(
|
||||||
|
sourceModules = listOf(input.toUri()),
|
||||||
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
|
)
|
||||||
val testOpts = CliTestOptions(junitDir = tempDir)
|
val testOpts = CliTestOptions(junitDir = tempDir)
|
||||||
val runner = CliTestRunner(opts, testOpts, noopWriter, noopWriter)
|
val runner = CliTestRunner(opts, testOpts, noopWriter, noopWriter)
|
||||||
assertThatCode { runner.run() }.hasMessageContaining("failed")
|
assertThatCode { runner.run() }.hasMessageContaining("failed")
|
||||||
@@ -474,6 +509,7 @@ class CliTestRunnerTest {
|
|||||||
CliBaseOptions(
|
CliBaseOptions(
|
||||||
sourceModules = listOf(input1.toUri(), input2.toUri()),
|
sourceModules = listOf(input1.toUri(), input2.toUri()),
|
||||||
settings = URI("pkl:settings"),
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
)
|
)
|
||||||
val testOpts = CliTestOptions(junitDir = tempDir, junitAggregateReports = true)
|
val testOpts = CliTestOptions(junitDir = tempDir, junitAggregateReports = true)
|
||||||
val runner = CliTestRunner(opts, testOpts, noopWriter, noopWriter)
|
val runner = CliTestRunner(opts, testOpts, noopWriter, noopWriter)
|
||||||
@@ -601,7 +637,12 @@ class CliTestRunnerTest {
|
|||||||
)
|
)
|
||||||
val out = StringWriter()
|
val out = StringWriter()
|
||||||
val err = StringWriter()
|
val err = StringWriter()
|
||||||
val opts = CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
|
val opts =
|
||||||
|
CliBaseOptions(
|
||||||
|
sourceModules = listOf(input.toUri()),
|
||||||
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
|
)
|
||||||
val testOpts = CliTestOptions()
|
val testOpts = CliTestOptions()
|
||||||
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
||||||
assertThatCode { runner.run() }.hasMessage("Tests failed.")
|
assertThatCode { runner.run() }.hasMessage("Tests failed.")
|
||||||
@@ -640,7 +681,12 @@ class CliTestRunnerTest {
|
|||||||
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
val input = tempDir.resolve("test.pkl").writeString(code).toString()
|
||||||
val out = StringWriter()
|
val out = StringWriter()
|
||||||
val err = StringWriter()
|
val err = StringWriter()
|
||||||
val opts = CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
|
val opts =
|
||||||
|
CliBaseOptions(
|
||||||
|
sourceModules = listOf(input.toUri()),
|
||||||
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
|
)
|
||||||
val testOpts = CliTestOptions()
|
val testOpts = CliTestOptions()
|
||||||
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
||||||
val exception = assertThrows<CliException> { runner.run() }
|
val exception = assertThrows<CliException> { runner.run() }
|
||||||
@@ -680,7 +726,11 @@ class CliTestRunnerTest {
|
|||||||
val out = StringWriter()
|
val out = StringWriter()
|
||||||
val err = StringWriter()
|
val err = StringWriter()
|
||||||
val opts =
|
val opts =
|
||||||
CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
|
CliBaseOptions(
|
||||||
|
sourceModules = listOf(input.toUri()),
|
||||||
|
settings = URI("pkl:settings"),
|
||||||
|
powerAssertionsEnabled = true,
|
||||||
|
)
|
||||||
val testOpts = CliTestOptions()
|
val testOpts = CliTestOptions()
|
||||||
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
|
||||||
runner.run()
|
runner.run()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -152,6 +152,9 @@ data class CliBaseOptions(
|
|||||||
|
|
||||||
/** Defines options for the formatting of calls to the trace() method. */
|
/** Defines options for the formatting of calls to the trace() method. */
|
||||||
val traceMode: TraceMode? = null,
|
val traceMode: TraceMode? = null,
|
||||||
|
|
||||||
|
/** Whether power assertions are enabled. */
|
||||||
|
val powerAssertionsEnabled: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -102,6 +102,7 @@ abstract class CliCommand(protected val cliOptions: CliBaseOptions) {
|
|||||||
cliOptions.timeout,
|
cliOptions.timeout,
|
||||||
stackFrameTransformer,
|
stackFrameTransformer,
|
||||||
envVars,
|
envVars,
|
||||||
|
cliOptions.powerAssertionsEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,5 +309,6 @@ abstract class CliCommand(protected val cliOptions: CliBaseOptions) {
|
|||||||
.setTimeout(cliOptions.timeout)
|
.setTimeout(cliOptions.timeout)
|
||||||
.setModuleCacheDir(moduleCacheDir)
|
.setModuleCacheDir(moduleCacheDir)
|
||||||
.setTraceMode(traceMode)
|
.setTraceMode(traceMode)
|
||||||
|
.setPowerAssertionsEnabled(cliOptions.powerAssertionsEnabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -316,6 +316,7 @@ class BaseOptions : OptionGroup() {
|
|||||||
modules: List<URI>,
|
modules: List<URI>,
|
||||||
projectOptions: ProjectOptions? = null,
|
projectOptions: ProjectOptions? = null,
|
||||||
testMode: Boolean = false,
|
testMode: Boolean = false,
|
||||||
|
powerAssertionsEnabled: Boolean = false,
|
||||||
): CliBaseOptions {
|
): CliBaseOptions {
|
||||||
return CliBaseOptions(
|
return CliBaseOptions(
|
||||||
sourceModules = modules,
|
sourceModules = modules,
|
||||||
@@ -343,6 +344,7 @@ class BaseOptions : OptionGroup() {
|
|||||||
externalModuleReaders = externalModuleReaders,
|
externalModuleReaders = externalModuleReaders,
|
||||||
externalResourceReaders = externalResourceReaders,
|
externalResourceReaders = externalResourceReaders,
|
||||||
traceMode = traceMode,
|
traceMode = traceMode,
|
||||||
|
powerAssertionsEnabled = powerAssertionsEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -120,7 +120,8 @@ public class Analyzer {
|
|||||||
? null
|
? null
|
||||||
: new ProjectDependenciesManager(
|
: new ProjectDependenciesManager(
|
||||||
projectDependencies, moduleResolver, securityManager),
|
projectDependencies, moduleResolver, securityManager),
|
||||||
traceMode));
|
traceMode,
|
||||||
|
false));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -70,6 +70,8 @@ public final class EvaluatorBuilder {
|
|||||||
|
|
||||||
private TraceMode traceMode = TraceMode.COMPACT;
|
private TraceMode traceMode = TraceMode.COMPACT;
|
||||||
|
|
||||||
|
private boolean powerAssertionsEnabled = false;
|
||||||
|
|
||||||
private EvaluatorBuilder() {}
|
private EvaluatorBuilder() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -468,6 +470,17 @@ public final class EvaluatorBuilder {
|
|||||||
return this.traceMode;
|
return this.traceMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Sets whether power assertions are enabled. */
|
||||||
|
public EvaluatorBuilder setPowerAssertionsEnabled(boolean powerAssertions) {
|
||||||
|
this.powerAssertionsEnabled = powerAssertions;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns whether power assertions are enabled. */
|
||||||
|
public boolean getPowerAssertionsEnabled() {
|
||||||
|
return powerAssertionsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a project, sets its dependencies, and also applies any evaluator settings if set.
|
* Given a project, sets its dependencies, and also applies any evaluator settings if set.
|
||||||
*
|
*
|
||||||
@@ -578,6 +591,7 @@ public final class EvaluatorBuilder {
|
|||||||
moduleCacheDir,
|
moduleCacheDir,
|
||||||
dependencies,
|
dependencies,
|
||||||
outputFormat,
|
outputFormat,
|
||||||
traceMode);
|
traceMode,
|
||||||
|
powerAssertionsEnabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -86,7 +86,8 @@ public final class EvaluatorImpl implements Evaluator {
|
|||||||
@Nullable Path moduleCacheDir,
|
@Nullable Path moduleCacheDir,
|
||||||
@Nullable DeclaredDependencies projectDependencies,
|
@Nullable DeclaredDependencies projectDependencies,
|
||||||
@Nullable String outputFormat,
|
@Nullable String outputFormat,
|
||||||
TraceMode traceMode) {
|
TraceMode traceMode,
|
||||||
|
boolean powerAssertions) {
|
||||||
|
|
||||||
securityManager = manager;
|
securityManager = manager;
|
||||||
frameTransformer = transformer;
|
frameTransformer = transformer;
|
||||||
@@ -115,7 +116,8 @@ public final class EvaluatorImpl implements Evaluator {
|
|||||||
? null
|
? null
|
||||||
: new ProjectDependenciesManager(
|
: new ProjectDependenciesManager(
|
||||||
projectDependencies, moduleResolver, securityManager),
|
projectDependencies, moduleResolver, securityManager),
|
||||||
traceMode));
|
traceMode,
|
||||||
|
powerAssertions));
|
||||||
});
|
});
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
// NOTE: would probably make sense to share executor between evaluators
|
// NOTE: would probably make sense to share executor between evaluators
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.pkl.core.ast.lambda.ApplyVmFunction1Node;
|
|||||||
import org.pkl.core.runtime.BaseModule;
|
import org.pkl.core.runtime.BaseModule;
|
||||||
import org.pkl.core.runtime.VmContext;
|
import org.pkl.core.runtime.VmContext;
|
||||||
import org.pkl.core.runtime.VmFunction;
|
import org.pkl.core.runtime.VmFunction;
|
||||||
|
import org.pkl.core.runtime.VmLanguage;
|
||||||
import org.pkl.core.runtime.VmUtils;
|
import org.pkl.core.runtime.VmUtils;
|
||||||
|
|
||||||
@NodeChild(value = "bodyNode", type = ExpressionNode.class)
|
@NodeChild(value = "bodyNode", type = ExpressionNode.class)
|
||||||
@@ -54,13 +55,26 @@ public abstract class TypeConstraintNode extends PklNode {
|
|||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
try (var valueTracker = VmContext.get(this).getValueTrackerFactory().create()) {
|
var vmContext = VmContext.get(this);
|
||||||
getBodyNode().executeGeneric(frame);
|
var localContext = VmLanguage.get(this).localContext.get();
|
||||||
|
// Use power assertions if enabled and not in type test or already instrumenting.
|
||||||
|
// This prevents `is` checks from triggering instrumentation, but allows them to
|
||||||
|
// participate if instrumentation is already active.
|
||||||
|
var usePowerAssertions =
|
||||||
|
vmContext.getPowerAssertionsEnabled()
|
||||||
|
&& (!localContext.isInTypeTest() || localContext.hasActiveTracker());
|
||||||
|
if (usePowerAssertions) {
|
||||||
|
try (var valueTracker = vmContext.getValueTrackerFactory().create()) {
|
||||||
|
getBodyNode().executeGeneric(frame);
|
||||||
|
throw new VmTypeMismatchException.Constraint(
|
||||||
|
sourceSection,
|
||||||
|
frame.getAuxiliarySlot(customThisSlot),
|
||||||
|
sourceSection,
|
||||||
|
valueTracker.values());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
throw new VmTypeMismatchException.Constraint(
|
throw new VmTypeMismatchException.Constraint(
|
||||||
sourceSection,
|
sourceSection, frame.getAuxiliarySlot(customThisSlot), sourceSection, null);
|
||||||
frame.getAuxiliarySlot(customThisSlot),
|
|
||||||
sourceSection,
|
|
||||||
valueTracker.values());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,10 +90,26 @@ public abstract class TypeConstraintNode extends PklNode {
|
|||||||
var result = applyNode.executeBoolean(function, value);
|
var result = applyNode.executeBoolean(function, value);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
try (var valueTracker = VmContext.get(this).getValueTrackerFactory().create()) {
|
var vmContext = VmContext.get(this);
|
||||||
applyNode.executeBoolean(function, value);
|
var localContext = VmLanguage.get(this).localContext.get();
|
||||||
|
// Use power assertions if enabled and not in type test or already instrumenting.
|
||||||
|
// This prevents `is` checks from triggering instrumentation, but allows them to
|
||||||
|
// participate if instrumentation is already active.
|
||||||
|
var usePowerAssertions =
|
||||||
|
vmContext.getPowerAssertionsEnabled()
|
||||||
|
&& (!localContext.isInTypeTest() || localContext.hasActiveTracker());
|
||||||
|
if (usePowerAssertions) {
|
||||||
|
try (var valueTracker = vmContext.getValueTrackerFactory().create()) {
|
||||||
|
applyNode.executeBoolean(function, value);
|
||||||
|
throw new VmTypeMismatchException.Constraint(
|
||||||
|
sourceSection,
|
||||||
|
value,
|
||||||
|
function.getRootNode().getSourceSection(),
|
||||||
|
valueTracker.values());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
throw new VmTypeMismatchException.Constraint(
|
throw new VmTypeMismatchException.Constraint(
|
||||||
sourceSection, value, function.getRootNode().getSourceSection(), valueTracker.values());
|
sourceSection, value, function.getRootNode().getSourceSection(), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,6 +20,7 @@ import com.oracle.truffle.api.frame.VirtualFrame;
|
|||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
|
import org.pkl.core.runtime.VmLanguage;
|
||||||
import org.pkl.core.util.Nullable;
|
import org.pkl.core.util.Nullable;
|
||||||
|
|
||||||
@NodeInfo(shortName = "is")
|
@NodeInfo(shortName = "is")
|
||||||
@@ -55,11 +56,16 @@ public final class TypeTestNode extends ExpressionNode {
|
|||||||
// TODO: throw if typeNode is FunctionTypeNode (it's impossible to check)
|
// TODO: throw if typeNode is FunctionTypeNode (it's impossible to check)
|
||||||
// https://github.com/apple/pkl/issues/639
|
// https://github.com/apple/pkl/issues/639
|
||||||
Object value = valueNode.executeGeneric(frame);
|
Object value = valueNode.executeGeneric(frame);
|
||||||
|
var localContext = VmLanguage.get(this).localContext.get();
|
||||||
|
boolean wasInTypeTest = localContext.isInTypeTest();
|
||||||
|
localContext.setInTypeTest(true);
|
||||||
try {
|
try {
|
||||||
typeNode.executeEagerly(frame, value);
|
typeNode.executeEagerly(frame, value);
|
||||||
return true;
|
return true;
|
||||||
} catch (VmTypeMismatchException e) {
|
} catch (VmTypeMismatchException e) {
|
||||||
return false;
|
return false;
|
||||||
|
} finally {
|
||||||
|
localContext.setInTypeTest(wasInTypeTest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,13 +171,13 @@ public abstract class VmTypeMismatchException extends ControlFlowException {
|
|||||||
public static final class Constraint extends VmTypeMismatchException {
|
public static final class Constraint extends VmTypeMismatchException {
|
||||||
|
|
||||||
private final SourceSection constraintBodySourceSection;
|
private final SourceSection constraintBodySourceSection;
|
||||||
private final Map<Node, List<Object>> trackedValues;
|
private final @Nullable Map<Node, List<Object>> trackedValues;
|
||||||
|
|
||||||
public Constraint(
|
public Constraint(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
Object actualValue,
|
Object actualValue,
|
||||||
SourceSection constraintBodySourceSection,
|
SourceSection constraintBodySourceSection,
|
||||||
Map<Node, List<Object>> trackedValues) {
|
@Nullable Map<Node, List<Object>> trackedValues) {
|
||||||
super(sourceSection, actualValue);
|
super(sourceSection, actualValue);
|
||||||
this.constraintBodySourceSection = constraintBodySourceSection;
|
this.constraintBodySourceSection = constraintBodySourceSection;
|
||||||
this.trackedValues = trackedValues;
|
this.trackedValues = trackedValues;
|
||||||
@@ -194,7 +194,7 @@ public abstract class VmTypeMismatchException extends ControlFlowException {
|
|||||||
.append(indent)
|
.append(indent)
|
||||||
.append("Value: ")
|
.append("Value: ")
|
||||||
.append(VmValueRenderer.singleLine(80 - indent.length()).render(actualValue));
|
.append(VmValueRenderer.singleLine(80 - indent.length()).render(actualValue));
|
||||||
if (!withPowerAssertions) {
|
if (!withPowerAssertions || trackedValues == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
builder.append("\n\n");
|
builder.append("\n\n");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -81,7 +81,8 @@ public final class Project {
|
|||||||
SecurityManager securityManager,
|
SecurityManager securityManager,
|
||||||
@Nullable java.time.Duration timeout,
|
@Nullable java.time.Duration timeout,
|
||||||
StackFrameTransformer stackFrameTransformer,
|
StackFrameTransformer stackFrameTransformer,
|
||||||
Map<String, String> envVars) {
|
Map<String, String> envVars,
|
||||||
|
boolean powerAssertionsEnabled) {
|
||||||
try (var evaluator =
|
try (var evaluator =
|
||||||
EvaluatorBuilder.unconfigured()
|
EvaluatorBuilder.unconfigured()
|
||||||
.setSecurityManager(securityManager)
|
.setSecurityManager(securityManager)
|
||||||
@@ -92,11 +93,29 @@ public final class Project {
|
|||||||
.addResourceReader(ResourceReaders.file())
|
.addResourceReader(ResourceReaders.file())
|
||||||
.addEnvironmentVariables(envVars)
|
.addEnvironmentVariables(envVars)
|
||||||
.setTimeout(timeout)
|
.setTimeout(timeout)
|
||||||
|
.setPowerAssertionsEnabled(powerAssertionsEnabled)
|
||||||
.build()) {
|
.build()) {
|
||||||
return load(evaluator, ModuleSource.path(path));
|
return load(evaluator, ModuleSource.path(path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads Project data from the given {@link Path}.
|
||||||
|
*
|
||||||
|
* <p>Evaluates a module's {@code output.value} to allow for embedding a project within a
|
||||||
|
* template.
|
||||||
|
*
|
||||||
|
* @throws PklException if an error occurred while evaluating the project file.
|
||||||
|
*/
|
||||||
|
public static Project loadFromPath(
|
||||||
|
Path path,
|
||||||
|
SecurityManager securityManager,
|
||||||
|
@Nullable java.time.Duration timeout,
|
||||||
|
StackFrameTransformer stackFrameTransformer,
|
||||||
|
Map<String, String> envVars) {
|
||||||
|
return loadFromPath(path, securityManager, timeout, stackFrameTransformer, envVars, false);
|
||||||
|
}
|
||||||
|
|
||||||
/** Convenience method to load a project with the default stack frame transformer. */
|
/** Convenience method to load a project with the default stack frame transformer. */
|
||||||
public static Project loadFromPath(
|
public static Project loadFromPath(
|
||||||
Path path, SecurityManager securityManager, @Nullable java.time.Duration timeout) {
|
Path path, SecurityManager securityManager, @Nullable java.time.Duration timeout) {
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ public class ReplServer implements AutoCloseable {
|
|||||||
outputFormat,
|
outputFormat,
|
||||||
packageResolver,
|
packageResolver,
|
||||||
projectDependenciesManager,
|
projectDependenciesManager,
|
||||||
traceMode));
|
traceMode,
|
||||||
|
true));
|
||||||
});
|
});
|
||||||
language = languageRef.get();
|
language = languageRef.get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,14 @@ import org.pkl.parser.syntax.StringPart.StringInterpolation;
|
|||||||
public class PowerAssertions {
|
public class PowerAssertions {
|
||||||
private PowerAssertions() {}
|
private PowerAssertions() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Power assertions can be enabled/disabled via CLI flags (--power-assertions /
|
||||||
|
* --no-power-assertions) or via EvaluatorBuilder.setPowerAssertions().
|
||||||
|
*/
|
||||||
|
public static boolean isEnabled() {
|
||||||
|
return VmContext.get(null).getPowerAssertionsEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
private static final VmValueRenderer vmValueRenderer = VmValueRenderer.singleLine(100);
|
private static final VmValueRenderer vmValueRenderer = VmValueRenderer.singleLine(100);
|
||||||
private static final Parser parser = new Parser();
|
private static final Parser parser = new Parser();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -51,7 +51,8 @@ public abstract class StdLibModule {
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
TraceMode.COMPACT));
|
TraceMode.COMPACT,
|
||||||
|
false));
|
||||||
var language = VmLanguage.get(null);
|
var language = VmLanguage.get(null);
|
||||||
var moduleKey = ModuleKeys.standardLibrary(uri);
|
var moduleKey = ModuleKeys.standardLibrary(uri);
|
||||||
var source = VmUtils.loadSource((ResolvedModuleKey) moduleKey);
|
var source = VmUtils.loadSource((ResolvedModuleKey) moduleKey);
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import org.pkl.core.util.AnsiTheme;
|
|||||||
import org.pkl.core.util.EconomicMaps;
|
import org.pkl.core.util.EconomicMaps;
|
||||||
import org.pkl.core.util.MutableBoolean;
|
import org.pkl.core.util.MutableBoolean;
|
||||||
import org.pkl.core.util.MutableReference;
|
import org.pkl.core.util.MutableReference;
|
||||||
|
import org.pkl.core.util.Nullable;
|
||||||
|
|
||||||
/** Runs test results examples and facts. */
|
/** Runs test results examples and facts. */
|
||||||
public final class TestRunner {
|
public final class TestRunner {
|
||||||
@@ -112,14 +113,20 @@ public final class TestRunner {
|
|||||||
try {
|
try {
|
||||||
var factValue = VmUtils.readMember(listing, idx);
|
var factValue = VmUtils.readMember(listing, idx);
|
||||||
if (factValue == Boolean.FALSE) {
|
if (factValue == Boolean.FALSE) {
|
||||||
try (var valueTracker = valueTrackerFactory.create()) {
|
if (PowerAssertions.isEnabled()) {
|
||||||
listing.cachedValues.clear();
|
try (var valueTracker = valueTrackerFactory.create()) {
|
||||||
VmUtils.readMember(listing, idx);
|
listing.cachedValues.clear();
|
||||||
|
VmUtils.readMember(listing, idx);
|
||||||
|
var failure =
|
||||||
|
factFailure(
|
||||||
|
member.getSourceSection(),
|
||||||
|
getDisplayUri(member),
|
||||||
|
valueTracker.values());
|
||||||
|
resultBuilder.addFailure(failure);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
var failure =
|
var failure =
|
||||||
factFailure(
|
factFailure(member.getSourceSection(), getDisplayUri(member), null);
|
||||||
member.getSourceSection(),
|
|
||||||
getDisplayUri(member),
|
|
||||||
valueTracker.values());
|
|
||||||
resultBuilder.addFailure(failure);
|
resultBuilder.addFailure(failure);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -408,17 +415,25 @@ public final class TestRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Failure factFailure(
|
private Failure factFailure(
|
||||||
SourceSection sourceSection, String location, Map<Node, List<Object>> trackedValues) {
|
SourceSection sourceSection,
|
||||||
|
String location,
|
||||||
|
@Nullable Map<Node, List<Object>> trackedValues) {
|
||||||
var sb = new AnsiStringBuilder(useColor);
|
var sb = new AnsiStringBuilder(useColor);
|
||||||
PowerAssertions.render(
|
if (trackedValues != null) {
|
||||||
sb,
|
PowerAssertions.render(
|
||||||
"",
|
sb,
|
||||||
sourceSection,
|
"",
|
||||||
trackedValues,
|
sourceSection,
|
||||||
(it) -> {
|
trackedValues,
|
||||||
it.append(" ");
|
(it) -> {
|
||||||
appendLocation(it, location);
|
it.append(" ");
|
||||||
});
|
appendLocation(it, location);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sb.append(sourceSection.getCharacters());
|
||||||
|
sb.append(" ");
|
||||||
|
appendLocation(sb, location);
|
||||||
|
}
|
||||||
return new Failure("Fact Failure", sb.toString());
|
return new Failure("Fact Failure", sb.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ public final class VmContext {
|
|||||||
private final VmValueTrackerFactory valueTrackerFactory;
|
private final VmValueTrackerFactory valueTrackerFactory;
|
||||||
|
|
||||||
public VmContext(VmLanguage vmLanguage, Env env) {
|
public VmContext(VmLanguage vmLanguage, Env env) {
|
||||||
this.valueTrackerFactory = new VmValueTrackerFactory(env.lookup(Instrumenter.class));
|
this.valueTrackerFactory =
|
||||||
|
new VmValueTrackerFactory(env.lookup(Instrumenter.class), vmLanguage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@LateInit private Holder holder;
|
@LateInit private Holder holder;
|
||||||
@@ -59,6 +60,7 @@ public final class VmContext {
|
|||||||
private final @Nullable PackageResolver packageResolver;
|
private final @Nullable PackageResolver packageResolver;
|
||||||
private final @Nullable ProjectDependenciesManager projectDependenciesManager;
|
private final @Nullable ProjectDependenciesManager projectDependenciesManager;
|
||||||
private final TraceMode traceMode;
|
private final TraceMode traceMode;
|
||||||
|
private final boolean powerAssertions;
|
||||||
|
|
||||||
public Holder(
|
public Holder(
|
||||||
StackFrameTransformer frameTransformer,
|
StackFrameTransformer frameTransformer,
|
||||||
@@ -73,7 +75,8 @@ public final class VmContext {
|
|||||||
@Nullable String outputFormat,
|
@Nullable String outputFormat,
|
||||||
@Nullable PackageResolver packageResolver,
|
@Nullable PackageResolver packageResolver,
|
||||||
@Nullable ProjectDependenciesManager projectDependenciesManager,
|
@Nullable ProjectDependenciesManager projectDependenciesManager,
|
||||||
TraceMode traceMode) {
|
TraceMode traceMode,
|
||||||
|
boolean powerAssertions) {
|
||||||
|
|
||||||
this.frameTransformer = frameTransformer;
|
this.frameTransformer = frameTransformer;
|
||||||
this.securityManager = securityManager;
|
this.securityManager = securityManager;
|
||||||
@@ -95,6 +98,7 @@ public final class VmContext {
|
|||||||
this.packageResolver = packageResolver;
|
this.packageResolver = packageResolver;
|
||||||
this.projectDependenciesManager = projectDependenciesManager;
|
this.projectDependenciesManager = projectDependenciesManager;
|
||||||
this.traceMode = traceMode;
|
this.traceMode = traceMode;
|
||||||
|
this.powerAssertions = powerAssertions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,6 +163,10 @@ public final class VmContext {
|
|||||||
return holder.traceMode;
|
return holder.traceMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getPowerAssertionsEnabled() {
|
||||||
|
return holder.powerAssertions;
|
||||||
|
}
|
||||||
|
|
||||||
public VmValueTrackerFactory getValueTrackerFactory() {
|
public VmValueTrackerFactory getValueTrackerFactory() {
|
||||||
return valueTrackerFactory;
|
return valueTrackerFactory;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2025-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -19,6 +19,15 @@ package org.pkl.core.runtime;
|
|||||||
public class VmLocalContext {
|
public class VmLocalContext {
|
||||||
private boolean shouldEagerTypecheck = false;
|
private boolean shouldEagerTypecheck = false;
|
||||||
|
|
||||||
|
/** Whether we are currently inside a type test ({@code is} check). */
|
||||||
|
private boolean inTypeTest = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of active {@link VmValueTracker} instances. Used to determine if instrumentation is
|
||||||
|
* already active.
|
||||||
|
*/
|
||||||
|
private int activeTrackerDepth = 0;
|
||||||
|
|
||||||
public VmLocalContext() {}
|
public VmLocalContext() {}
|
||||||
|
|
||||||
public void shouldEagerTypecheck(boolean shouldEagerTypecheck) {
|
public void shouldEagerTypecheck(boolean shouldEagerTypecheck) {
|
||||||
@@ -28,4 +37,24 @@ public class VmLocalContext {
|
|||||||
public boolean shouldEagerTypecheck() {
|
public boolean shouldEagerTypecheck() {
|
||||||
return this.shouldEagerTypecheck;
|
return this.shouldEagerTypecheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setInTypeTest(boolean inTypeTest) {
|
||||||
|
this.inTypeTest = inTypeTest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInTypeTest() {
|
||||||
|
return inTypeTest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterTracker() {
|
||||||
|
activeTrackerDepth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exitTracker() {
|
||||||
|
activeTrackerDepth--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasActiveTracker() {
|
||||||
|
return activeTrackerDepth > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,10 +32,13 @@ import org.pkl.core.util.Nullable;
|
|||||||
public final class VmValueTracker implements AutoCloseable {
|
public final class VmValueTracker implements AutoCloseable {
|
||||||
|
|
||||||
private final EventBinding<ExecutionEventNodeFactory> binding;
|
private final EventBinding<ExecutionEventNodeFactory> binding;
|
||||||
|
private final VmLocalContext localContext;
|
||||||
|
|
||||||
private final Map<Node, List<Object>> values = new IdentityHashMap<>();
|
private final Map<Node, List<Object>> values = new IdentityHashMap<>();
|
||||||
|
|
||||||
public VmValueTracker(Instrumenter instrumenter) {
|
public VmValueTracker(Instrumenter instrumenter, VmLocalContext localContext) {
|
||||||
|
this.localContext = localContext;
|
||||||
|
localContext.enterTracker();
|
||||||
binding =
|
binding =
|
||||||
instrumenter.attachExecutionEventFactory(
|
instrumenter.attachExecutionEventFactory(
|
||||||
SourceSectionFilter.newBuilder().tagIs(PklTags.Expression.class).build(),
|
SourceSectionFilter.newBuilder().tagIs(PklTags.Expression.class).build(),
|
||||||
@@ -61,6 +64,7 @@ public final class VmValueTracker implements AutoCloseable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
localContext.exitTracker();
|
||||||
binding.dispose();
|
binding.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,15 @@ import com.oracle.truffle.api.instrumentation.Instrumenter;
|
|||||||
public final class VmValueTrackerFactory {
|
public final class VmValueTrackerFactory {
|
||||||
|
|
||||||
private final Instrumenter instrumenter;
|
private final Instrumenter instrumenter;
|
||||||
|
private final VmLanguage language;
|
||||||
|
|
||||||
public VmValueTrackerFactory(Instrumenter instrumenter) {
|
public VmValueTrackerFactory(Instrumenter instrumenter, VmLanguage language) {
|
||||||
this.instrumenter = instrumenter;
|
this.instrumenter = instrumenter;
|
||||||
|
this.language = language;
|
||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
public VmValueTracker create() {
|
public VmValueTracker create() {
|
||||||
return new VmValueTracker(instrumenter);
|
return new VmValueTracker(instrumenter, language.localContext.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import org.pkl.core.ModuleSource.*
|
|||||||
|
|
||||||
class EvaluateTestsTest {
|
class EvaluateTestsTest {
|
||||||
|
|
||||||
private val evaluator = Evaluator.preconfigured()
|
private val evaluator = EvaluatorBuilder.preconfigured().setPowerAssertionsEnabled(true).build()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test successful module`() {
|
fun `test successful module`() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -178,6 +178,7 @@ class LanguageSnippetTestsEngine : AbstractLanguageSnippetTestsEngine() {
|
|||||||
.addCertificates(FileTestUtils.selfSignedCertificate)
|
.addCertificates(FileTestUtils.selfSignedCertificate)
|
||||||
.buildLazily()
|
.buildLazily()
|
||||||
)
|
)
|
||||||
|
.setPowerAssertionsEnabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val testClass: KClass<*> = LanguageSnippetTests::class
|
override val testClass: KClass<*> = LanguageSnippetTests::class
|
||||||
@@ -200,6 +201,7 @@ class LanguageSnippetTestsEngine : AbstractLanguageSnippetTestsEngine() {
|
|||||||
null,
|
null,
|
||||||
StackFrameTransformers.empty,
|
StackFrameTransformers.empty,
|
||||||
mapOf(),
|
mapOf(),
|
||||||
|
true, // enable power assertions for tests
|
||||||
)
|
)
|
||||||
securityManager = null
|
securityManager = null
|
||||||
applyFromProject(project)
|
applyFromProject(project)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -146,6 +146,10 @@ public abstract class BasePklTask extends DefaultTask {
|
|||||||
@Optional
|
@Optional
|
||||||
public abstract MapProperty<URI, URI> getHttpRewrites();
|
public abstract MapProperty<URI, URI> getHttpRewrites();
|
||||||
|
|
||||||
|
@Input
|
||||||
|
@Optional
|
||||||
|
public abstract Property<Boolean> getPowerAssertions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There are issues with using native libraries in Gradle plugins. As a workaround for now, make
|
* There are issues with using native libraries in Gradle plugins. As a workaround for now, make
|
||||||
* Truffle use an un-optimized runtime.
|
* Truffle use an un-optimized runtime.
|
||||||
@@ -202,7 +206,8 @@ public abstract class BasePklTask extends DefaultTask {
|
|||||||
getHttpRewrites().getOrNull(),
|
getHttpRewrites().getOrNull(),
|
||||||
Map.of(),
|
Map.of(),
|
||||||
Map.of(),
|
Map.of(),
|
||||||
null);
|
null,
|
||||||
|
getPowerAssertions().getOrElse(false));
|
||||||
}
|
}
|
||||||
return cachedOptions;
|
return cachedOptions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -166,7 +166,8 @@ public abstract class ModulesTask extends BasePklTask {
|
|||||||
getHttpRewrites().getOrNull(),
|
getHttpRewrites().getOrNull(),
|
||||||
Map.of(),
|
Map.of(),
|
||||||
Map.of(),
|
Map.of(),
|
||||||
null);
|
null,
|
||||||
|
getPowerAssertions().getOrElse(false));
|
||||||
}
|
}
|
||||||
return cachedOptions;
|
return cachedOptions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -41,6 +41,7 @@ public abstract class TestTask extends ModulesTask {
|
|||||||
|
|
||||||
public TestTask() {
|
public TestTask() {
|
||||||
this.getJunitAggregateSuiteName().convention("pkl-tests");
|
this.getJunitAggregateSuiteName().convention("pkl-tests");
|
||||||
|
this.getPowerAssertions().convention(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user