mirror of
https://github.com/apple/pkl.git
synced 2026-04-24 09:18:35 +02:00
Improve testing with stats and errors per test section (#498)
* Emojis are moves to the left to be aligned * A summary line is added with test counts * Facts and Examples are grouped under their own section
This commit is contained in:
@@ -60,13 +60,16 @@ constructor(
|
|||||||
evaluator.use {
|
evaluator.use {
|
||||||
var failed = false
|
var failed = false
|
||||||
val moduleNames = mutableSetOf<String>()
|
val moduleNames = mutableSetOf<String>()
|
||||||
for (moduleUri in sources) {
|
for ((idx, moduleUri) in sources.withIndex()) {
|
||||||
try {
|
try {
|
||||||
val results = evaluator.evaluateTest(uri(moduleUri), testOptions.overwrite)
|
val results = evaluator.evaluateTest(uri(moduleUri), testOptions.overwrite)
|
||||||
if (!failed) {
|
if (!failed) {
|
||||||
failed = results.failed()
|
failed = results.failed()
|
||||||
}
|
}
|
||||||
SimpleReport().report(results, consoleWriter)
|
SimpleReport().report(results, consoleWriter)
|
||||||
|
if (sources.size > 1 && idx != sources.size - 1) {
|
||||||
|
consoleWriter.append('\n')
|
||||||
|
}
|
||||||
consoleWriter.flush()
|
consoleWriter.flush()
|
||||||
val junitDir = testOptions.junitDir
|
val junitDir = testOptions.junitDir
|
||||||
if (junitDir != null) {
|
if (junitDir != null) {
|
||||||
|
|||||||
@@ -63,8 +63,10 @@ class CliTestRunnerTest {
|
|||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
"""
|
"""
|
||||||
module test
|
module test
|
||||||
succeed ✅
|
facts
|
||||||
|
✅ succeed
|
||||||
|
✅ 100.0% tests pass [1 passed], 100.0% asserts pass [2 passed]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
.trimIndent()
|
.trimIndent()
|
||||||
)
|
)
|
||||||
@@ -80,7 +82,7 @@ class CliTestRunnerTest {
|
|||||||
facts {
|
facts {
|
||||||
["fail"] {
|
["fail"] {
|
||||||
4 == 9
|
4 == 9
|
||||||
"foo" == "bar"
|
"foo" != "bar"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@@ -97,10 +99,11 @@ class CliTestRunnerTest {
|
|||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
"""
|
"""
|
||||||
module test
|
module test
|
||||||
fail ❌
|
facts
|
||||||
4 == 9 ❌
|
❌ fail
|
||||||
"foo" == "bar" ❌
|
4 == 9
|
||||||
|
❌ 0.0% tests pass [1/1 failed], 50.0% asserts pass [1/2 failed]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
.trimIndent()
|
.trimIndent()
|
||||||
)
|
)
|
||||||
@@ -132,14 +135,15 @@ class CliTestRunnerTest {
|
|||||||
.isEqualToNormalizingNewlines(
|
.isEqualToNormalizingNewlines(
|
||||||
"""
|
"""
|
||||||
module test
|
module test
|
||||||
fail ❌
|
facts
|
||||||
Error:
|
❌ fail
|
||||||
–– Pkl Error ––
|
–– Pkl Error ––
|
||||||
uh oh
|
uh oh
|
||||||
|
|
||||||
5 | throw("uh oh")
|
5 | throw("uh oh")
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
at test#facts["fail"][#1]
|
at test#facts["fail"][#1]
|
||||||
|
❌ 0.0% tests pass [1/1 failed], 0.0% asserts pass [1/1 failed]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
.trimIndent()
|
.trimIndent()
|
||||||
@@ -172,14 +176,15 @@ class CliTestRunnerTest {
|
|||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
"""
|
"""
|
||||||
module test
|
module test
|
||||||
fail ❌
|
examples
|
||||||
Error:
|
❌ fail
|
||||||
–– Pkl Error ––
|
–– Pkl Error ––
|
||||||
uh oh
|
uh oh
|
||||||
|
|
||||||
5 | throw("uh oh")
|
5 | throw("uh oh")
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
at test#examples["fail"][#1]
|
at test#examples["fail"][#1]
|
||||||
|
❌ 0.0% tests pass [1/1 failed], 0.0% asserts pass [1/1 failed]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
.trimIndent()
|
.trimIndent()
|
||||||
@@ -226,14 +231,15 @@ class CliTestRunnerTest {
|
|||||||
.isEqualToNormalizingNewlines(
|
.isEqualToNormalizingNewlines(
|
||||||
"""
|
"""
|
||||||
module test
|
module test
|
||||||
fail ❌
|
examples
|
||||||
Error:
|
❌ fail
|
||||||
–– Pkl Error ––
|
–– Pkl Error ––
|
||||||
uh oh
|
uh oh
|
||||||
|
|
||||||
5 | throw("uh oh")
|
5 | throw("uh oh")
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
at test#examples["fail"][#1]
|
at test#examples["fail"][#1]
|
||||||
|
❌ 0.0% tests pass [1/1 failed], 0.0% asserts pass [1/1 failed]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
.trimIndent()
|
.trimIndent()
|
||||||
@@ -252,7 +258,8 @@ class CliTestRunnerTest {
|
|||||||
9 == trace(9)
|
9 == trace(9)
|
||||||
"foo" == "foo"
|
"foo" == "foo"
|
||||||
}
|
}
|
||||||
["fail"] {
|
["bar"] {
|
||||||
|
"foo" == "foo"
|
||||||
5 == 9
|
5 == 9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,9 +277,9 @@ class CliTestRunnerTest {
|
|||||||
"""
|
"""
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<testsuite name="test" tests="2" failures="1">
|
<testsuite name="test" tests="2" failures="1">
|
||||||
<testcase classname="test" name="foo"></testcase>
|
<testcase classname="test.facts" name="foo"></testcase>
|
||||||
<testcase classname="test" name="fail">
|
<testcase classname="test.facts" name="bar">
|
||||||
<failure message="Fact Failure">5 == 9 ❌</failure>
|
<failure message="Fact Failure">5 == 9</failure>
|
||||||
</testcase>
|
</testcase>
|
||||||
<system-err><![CDATA[9 = 9
|
<system-err><![CDATA[9 = 9
|
||||||
]]></system-err>
|
]]></system-err>
|
||||||
@@ -311,9 +318,9 @@ class CliTestRunnerTest {
|
|||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
"""
|
"""
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<testsuite name="test" tests="2" failures="0">
|
<testsuite name="test" tests="2" failures="1">
|
||||||
<testcase classname="test" name="foo"></testcase>
|
<testcase classname="test.facts" name="foo"></testcase>
|
||||||
<testcase classname="test" name="fail">
|
<testcase classname="test.facts" name="fail">
|
||||||
<error message="uh oh">–– Pkl Error ––
|
<error message="uh oh">–– Pkl Error ––
|
||||||
uh oh
|
uh oh
|
||||||
|
|
||||||
|
|||||||
@@ -20,61 +20,40 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.pkl.core.PklException;
|
import org.pkl.core.PklException;
|
||||||
|
import org.pkl.core.runtime.TestResults.TestSectionResults.TestSection;
|
||||||
|
|
||||||
/** Aggregate test results for a module. Used to verify test failures and generate reports. */
|
/** Aggregate test results for a module. Used to verify test failures and generate reports. */
|
||||||
public final class TestResults {
|
public final class TestResults {
|
||||||
|
public final String moduleName;
|
||||||
private final String module;
|
public final String displayUri;
|
||||||
private final String displayUri;
|
public final TestSectionResults module = new TestSectionResults(TestSection.MODULE);
|
||||||
private final List<TestResult> results = new ArrayList<>();
|
public final TestSectionResults facts = new TestSectionResults(TestSection.FACTS);
|
||||||
|
public final TestSectionResults examples = new TestSectionResults(TestSection.EXAMPLES);
|
||||||
private String err = "";
|
private String err = "";
|
||||||
|
|
||||||
public TestResults(String module, String displayUri) {
|
public TestResults(String moduleName, String displayUri) {
|
||||||
this.module = module;
|
this.moduleName = moduleName;
|
||||||
this.displayUri = displayUri;
|
this.displayUri = displayUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getModuleName() {
|
|
||||||
return module;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplayUri() {
|
|
||||||
return displayUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TestResult> getResults() {
|
|
||||||
return Collections.unmodifiableList(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TestResult newResult(String name) {
|
|
||||||
var result = new TestResult(name);
|
|
||||||
results.add(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void newResult(String name, Failure failure) {
|
|
||||||
var result = new TestResult(name);
|
|
||||||
result.addFailure(failure);
|
|
||||||
results.add(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int totalTests() {
|
public int totalTests() {
|
||||||
return results.size();
|
return module.totalTests() + facts.totalTests() + examples.totalTests();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int totalFailures() {
|
public int totalFailures() {
|
||||||
int total = 0;
|
return module.totalFailures() + facts.totalFailures() + examples.totalFailures();
|
||||||
for (var res : results) {
|
}
|
||||||
total += res.getFailures().size();
|
|
||||||
}
|
public int totalAsserts() {
|
||||||
return total;
|
return module.totalAsserts() + facts.totalAsserts() + examples.totalAsserts();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int totalAssertsFailed() {
|
||||||
|
return module.totalAssertsFailed() + facts.totalAssertsFailed() + examples.totalAssertsFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean failed() {
|
public boolean failed() {
|
||||||
for (var res : results) {
|
return module.failed() || facts.failed() || examples.failed();
|
||||||
if (res.isFailure()) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getErr() {
|
public String getErr() {
|
||||||
@@ -85,147 +64,295 @@ public final class TestResults {
|
|||||||
this.err = err;
|
this.err = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TestResult {
|
public static class TestSectionResults {
|
||||||
|
public final TestSection name;
|
||||||
|
private final List<TestResult> results = new ArrayList<>();
|
||||||
|
private Error error;
|
||||||
|
|
||||||
private final String name;
|
public TestSectionResults(TestSection name) {
|
||||||
private final List<Failure> failures = new ArrayList<>();
|
|
||||||
private final List<Error> errors = new ArrayList<>();
|
|
||||||
private boolean isExampleWritten = false;
|
|
||||||
|
|
||||||
public TestResult(String name) {
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSuccess() {
|
public void setError(Error error) {
|
||||||
return failures.isEmpty() && errors.isEmpty();
|
this.error = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isFailure() {
|
public Error getError() {
|
||||||
return !isSuccess();
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public boolean hasError() {
|
||||||
return name;
|
return error != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isExampleWritten() {
|
public List<TestResult> getResults() {
|
||||||
return isExampleWritten;
|
return Collections.unmodifiableList(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExampleWritten(boolean exampleWritten) {
|
public TestResult newResult(String name) {
|
||||||
isExampleWritten = exampleWritten;
|
var result = new TestResult(name, this.name == TestSection.EXAMPLES);
|
||||||
|
results.add(result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Failure> getFailures() {
|
public TestResult newResult(String name, Failure failure) {
|
||||||
return Collections.unmodifiableList(failures);
|
var result = new TestResult(name, this.name == TestSection.EXAMPLES);
|
||||||
|
result.addFailure(failure);
|
||||||
|
results.add(result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addFailure(Failure description) {
|
public TestResult newResult(String name, Error error) {
|
||||||
failures.add(description);
|
var result = new TestResult(name, this.name == TestSection.EXAMPLES);
|
||||||
|
result.addError(error);
|
||||||
|
results.add(result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Error> getErrors() {
|
public int totalTests() {
|
||||||
return Collections.unmodifiableList(errors);
|
var total = results.size();
|
||||||
|
return (hasError() ? ++total : total);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addError(Error err) {
|
public int totalAsserts() {
|
||||||
errors.add(err);
|
int total = 0;
|
||||||
}
|
for (var res : results) {
|
||||||
}
|
total += res.totalAsserts();
|
||||||
|
|
||||||
public static class Failure {
|
|
||||||
|
|
||||||
private final String kind;
|
|
||||||
private final String rendered;
|
|
||||||
|
|
||||||
private Failure(String kind, String rendered) {
|
|
||||||
this.kind = kind;
|
|
||||||
this.rendered = rendered;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKind() {
|
|
||||||
return kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRendered() {
|
|
||||||
return rendered;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Failure buildFactFailure(SourceSection sourceSection, String description) {
|
|
||||||
return new Failure(
|
|
||||||
"Fact Failure", sourceSection.getCharacters() + " ❌ (" + description + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Failure buildExampleLengthMismatchFailure(
|
|
||||||
String location, String property, int expectedLength, int actualLength) {
|
|
||||||
String builder =
|
|
||||||
"("
|
|
||||||
+ location
|
|
||||||
+ ")\n"
|
|
||||||
+ "Output mismatch: Expected \""
|
|
||||||
+ property
|
|
||||||
+ "\" to contain "
|
|
||||||
+ expectedLength
|
|
||||||
+ " examples, but found "
|
|
||||||
+ actualLength;
|
|
||||||
return new Failure("Output Mismatch (Length)", builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Failure buildExamplePropertyMismatchFailure(
|
|
||||||
String location, String property, boolean isMissingInExpected) {
|
|
||||||
var builder = new StringBuilder();
|
|
||||||
builder
|
|
||||||
.append("(")
|
|
||||||
.append(location)
|
|
||||||
.append(")\n")
|
|
||||||
.append("Output mismatch: \"")
|
|
||||||
.append(property);
|
|
||||||
if (isMissingInExpected) {
|
|
||||||
builder.append("\" exists in actual but not in expected output");
|
|
||||||
} else {
|
|
||||||
builder.append("\" exists in expected but not in actual output");
|
|
||||||
}
|
}
|
||||||
return new Failure("Output Mismatch", builder.toString());
|
return (hasError() ? ++total : total);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Failure buildExampleFailure(
|
public int totalAssertsFailed() {
|
||||||
String location,
|
int total = 0;
|
||||||
String expectedLocation,
|
for (var res : results) {
|
||||||
String expectedValue,
|
total += res.totalAssertsFailed();
|
||||||
String actualLocation,
|
}
|
||||||
String actualValue) {
|
return (hasError() ? ++total : total);
|
||||||
String builder =
|
|
||||||
"("
|
|
||||||
+ location
|
|
||||||
+ ")\n"
|
|
||||||
+ "Expected: ("
|
|
||||||
+ expectedLocation
|
|
||||||
+ ")\n"
|
|
||||||
+ expectedValue
|
|
||||||
+ "\nActual: ("
|
|
||||||
+ actualLocation
|
|
||||||
+ ")\n"
|
|
||||||
+ actualValue;
|
|
||||||
return new Failure("Example Failure", builder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Error {
|
|
||||||
|
|
||||||
private final String message;
|
|
||||||
private final PklException exception;
|
|
||||||
|
|
||||||
public Error(String message, PklException exception) {
|
|
||||||
this.message = message;
|
|
||||||
this.exception = exception;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
public int totalFailures() {
|
||||||
return message;
|
int total = 0;
|
||||||
|
for (var res : results) {
|
||||||
|
if (res.isFailure()) total++;
|
||||||
|
}
|
||||||
|
return (hasError() ? ++total : total);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Exception getException() {
|
public boolean failed() {
|
||||||
return exception;
|
if (hasError()) return true;
|
||||||
|
|
||||||
|
for (var res : results) {
|
||||||
|
if (res.isFailure()) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestResult {
|
||||||
|
public final String name;
|
||||||
|
private int totalAsserts = 0;
|
||||||
|
private int totalAssertsFailed = 0;
|
||||||
|
private final List<Failure> failures = new ArrayList<>();
|
||||||
|
private final List<Error> errors = new ArrayList<>();
|
||||||
|
public final boolean isExample;
|
||||||
|
private boolean isExampleWritten = false;
|
||||||
|
|
||||||
|
public TestResult(String name, boolean isExample) {
|
||||||
|
this.name = name;
|
||||||
|
this.isExample = isExample;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return failures.isEmpty() && errors.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFailure() {
|
||||||
|
return !isSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExampleWritten() {
|
||||||
|
return isExampleWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExampleWritten(boolean exampleWritten) {
|
||||||
|
isExampleWritten = exampleWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Failure> getFailures() {
|
||||||
|
return Collections.unmodifiableList(failures);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFailure(Failure description) {
|
||||||
|
failures.add(description);
|
||||||
|
totalAssertsFailed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Error> getErrors() {
|
||||||
|
return Collections.unmodifiableList(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addError(Error err) {
|
||||||
|
errors.add(err);
|
||||||
|
totalAssertsFailed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int totalAsserts() {
|
||||||
|
return totalAsserts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void countAssert() {
|
||||||
|
totalAsserts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int totalAssertsFailed() {
|
||||||
|
return totalAssertsFailed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Failure {
|
||||||
|
|
||||||
|
private final String kind;
|
||||||
|
private final String failure;
|
||||||
|
private final String location;
|
||||||
|
|
||||||
|
private Failure(String kind, String failure, String location) {
|
||||||
|
this.kind = kind;
|
||||||
|
this.failure = failure;
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKind() {
|
||||||
|
return kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFailure() {
|
||||||
|
return failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String renderLocation(String location) {
|
||||||
|
return "(" + location + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRendered() {
|
||||||
|
String rendered;
|
||||||
|
|
||||||
|
if (kind == "Fact Failure") {
|
||||||
|
rendered = failure + " " + renderLocation(getLocation());
|
||||||
|
} else {
|
||||||
|
rendered = renderLocation(getLocation()) + "\n" + failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rendered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Failure buildFactFailure(SourceSection sourceSection, String location) {
|
||||||
|
return new Failure("Fact Failure", sourceSection.getCharacters().toString(), location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Failure buildExampleLengthMismatchFailure(
|
||||||
|
String location, String property, int expectedLength, int actualLength) {
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder
|
||||||
|
.append("Output mismatch: Expected \"")
|
||||||
|
.append(property)
|
||||||
|
.append("\" to contain ")
|
||||||
|
.append(expectedLength)
|
||||||
|
.append(" examples, but found ")
|
||||||
|
.append(actualLength);
|
||||||
|
|
||||||
|
return new Failure("Output Mismatch (Length)", builder.toString(), location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Failure buildExamplePropertyMismatchFailure(
|
||||||
|
String location, String property, boolean isMissingInExpected) {
|
||||||
|
|
||||||
|
String exists_in;
|
||||||
|
String missing_in;
|
||||||
|
|
||||||
|
if (isMissingInExpected) {
|
||||||
|
exists_in = "actual";
|
||||||
|
missing_in = "expected";
|
||||||
|
} else {
|
||||||
|
exists_in = "expected";
|
||||||
|
missing_in = "actual";
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder
|
||||||
|
.append("Output mismatch: \"")
|
||||||
|
.append(property)
|
||||||
|
.append("\" exists in ")
|
||||||
|
.append(exists_in)
|
||||||
|
.append(" but not in ")
|
||||||
|
.append(missing_in)
|
||||||
|
.append(" output");
|
||||||
|
|
||||||
|
return new Failure("Output Mismatch", builder.toString(), location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Failure buildExampleFailure(
|
||||||
|
String location,
|
||||||
|
String expectedLocation,
|
||||||
|
String expectedValue,
|
||||||
|
String actualLocation,
|
||||||
|
String actualValue) {
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder
|
||||||
|
.append("Expected: ")
|
||||||
|
.append(renderLocation(expectedLocation))
|
||||||
|
.append("\n")
|
||||||
|
.append(expectedValue)
|
||||||
|
.append("\n")
|
||||||
|
.append("Actual: ")
|
||||||
|
.append(renderLocation(actualLocation))
|
||||||
|
.append("\n")
|
||||||
|
.append(actualValue);
|
||||||
|
|
||||||
|
return new Failure("Example Failure", builder.toString(), location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Error {
|
||||||
|
|
||||||
|
private final String message;
|
||||||
|
private final PklException exception;
|
||||||
|
|
||||||
|
public Error(String message, PklException exception) {
|
||||||
|
this.message = message;
|
||||||
|
this.exception = exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Exception getException() {
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRendered() {
|
||||||
|
return exception.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TestSection {
|
||||||
|
MODULE("module"),
|
||||||
|
FACTS("facts"),
|
||||||
|
EXAMPLES("examples");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
TestSection(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ import org.pkl.core.BufferedLogger;
|
|||||||
import org.pkl.core.StackFrameTransformer;
|
import org.pkl.core.StackFrameTransformer;
|
||||||
import org.pkl.core.ast.member.ObjectMember;
|
import org.pkl.core.ast.member.ObjectMember;
|
||||||
import org.pkl.core.module.ModuleKeys;
|
import org.pkl.core.module.ModuleKeys;
|
||||||
import org.pkl.core.runtime.TestResults.Error;
|
import org.pkl.core.runtime.TestResults.TestSectionResults;
|
||||||
import org.pkl.core.runtime.TestResults.Failure;
|
import org.pkl.core.runtime.TestResults.TestSectionResults.Error;
|
||||||
|
import org.pkl.core.runtime.TestResults.TestSectionResults.Failure;
|
||||||
import org.pkl.core.stdlib.PklConverter;
|
import org.pkl.core.stdlib.PklConverter;
|
||||||
import org.pkl.core.stdlib.base.PcfRenderer;
|
import org.pkl.core.stdlib.base.PcfRenderer;
|
||||||
import org.pkl.core.util.EconomicMaps;
|
import org.pkl.core.util.EconomicMaps;
|
||||||
@@ -51,12 +52,25 @@ public final class TestRunner {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
checkAmendsPklTest(testModule);
|
checkAmendsPklTest(testModule);
|
||||||
runFacts(testModule, results);
|
|
||||||
runExamples(testModule, info, results);
|
|
||||||
} catch (VmException v) {
|
} catch (VmException v) {
|
||||||
var meta = results.newResult(info.getModuleName());
|
var error = new Error(v.getMessage(), v.toPklException(stackFrameTransformer));
|
||||||
meta.addError(new Error(v.getMessage(), v.toPklException(stackFrameTransformer)));
|
results.module.setError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
runFacts(testModule, results.facts);
|
||||||
|
} catch (VmException v) {
|
||||||
|
var error = new Error(v.getMessage(), v.toPklException(stackFrameTransformer));
|
||||||
|
results.facts.setError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
runExamples(testModule, info, results.examples);
|
||||||
|
} catch (VmException v) {
|
||||||
|
var error = new Error(v.getMessage(), v.toPklException(stackFrameTransformer));
|
||||||
|
results.examples.setError(error);
|
||||||
|
}
|
||||||
|
|
||||||
results.setErr(logger.getLogs());
|
results.setErr(logger.getLogs());
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
@@ -72,7 +86,7 @@ public final class TestRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runFacts(VmTyped testModule, TestResults results) {
|
private void runFacts(VmTyped testModule, TestSectionResults results) {
|
||||||
var facts = VmUtils.readMember(testModule, Identifier.FACTS);
|
var facts = VmUtils.readMember(testModule, Identifier.FACTS);
|
||||||
if (facts instanceof VmNull) return;
|
if (facts instanceof VmNull) return;
|
||||||
|
|
||||||
@@ -86,6 +100,9 @@ public final class TestRunner {
|
|||||||
if (member.isLocalOrExternalOrHidden()) {
|
if (member.isLocalOrExternalOrHidden()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.countAssert();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var factValue = VmUtils.readMember(listing, idx);
|
var factValue = VmUtils.readMember(listing, idx);
|
||||||
if (factValue == Boolean.FALSE) {
|
if (factValue == Boolean.FALSE) {
|
||||||
@@ -101,7 +118,7 @@ public final class TestRunner {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runExamples(VmTyped testModule, ModuleInfo info, TestResults results) {
|
private void runExamples(VmTyped testModule, ModuleInfo info, TestSectionResults results) {
|
||||||
var examples = VmUtils.readMember(testModule, Identifier.EXAMPLES);
|
var examples = VmUtils.readMember(testModule, Identifier.EXAMPLES);
|
||||||
if (examples instanceof VmNull) return;
|
if (examples instanceof VmNull) return;
|
||||||
|
|
||||||
@@ -144,7 +161,10 @@ public final class TestRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doRunAndValidateExamples(
|
private void doRunAndValidateExamples(
|
||||||
VmMapping examples, Path expectedOutputFile, Path actualOutputFile, TestResults results) {
|
VmMapping examples,
|
||||||
|
Path expectedOutputFile,
|
||||||
|
Path actualOutputFile,
|
||||||
|
TestSectionResults results) {
|
||||||
var expectedExampleOutputs = loadExampleOutputs(expectedOutputFile);
|
var expectedExampleOutputs = loadExampleOutputs(expectedOutputFile);
|
||||||
var actualExampleOutputs = new MutableReference<VmDynamic>(null);
|
var actualExampleOutputs = new MutableReference<VmDynamic>(null);
|
||||||
var allGroupsSucceeded = new MutableBoolean(true);
|
var allGroupsSucceeded = new MutableBoolean(true);
|
||||||
@@ -155,23 +175,27 @@ public final class TestRunner {
|
|||||||
var group = (VmListing) groupValue;
|
var group = (VmListing) groupValue;
|
||||||
var expectedGroup =
|
var expectedGroup =
|
||||||
(VmDynamic) VmUtils.readMemberOrNull(expectedExampleOutputs, groupKey);
|
(VmDynamic) VmUtils.readMemberOrNull(expectedExampleOutputs, groupKey);
|
||||||
var result = results.newResult(testName);
|
|
||||||
|
|
||||||
if (expectedGroup == null) {
|
if (expectedGroup == null) {
|
||||||
results.newResult(
|
results
|
||||||
testName,
|
.newResult(
|
||||||
Failure.buildExamplePropertyMismatchFailure(
|
testName,
|
||||||
getDisplayUri(groupMember), String.valueOf(groupKey), true));
|
Failure.buildExamplePropertyMismatchFailure(
|
||||||
|
getDisplayUri(groupMember), testName, true))
|
||||||
|
.countAssert();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group.getLength() != expectedGroup.getLength()) {
|
if (group.getLength() != expectedGroup.getLength()) {
|
||||||
result.addFailure(
|
results
|
||||||
Failure.buildExampleLengthMismatchFailure(
|
.newResult(
|
||||||
getDisplayUri(groupMember),
|
testName,
|
||||||
String.valueOf(groupKey),
|
Failure.buildExampleLengthMismatchFailure(
|
||||||
expectedGroup.getLength(),
|
getDisplayUri(groupMember),
|
||||||
group.getLength()));
|
testName,
|
||||||
|
expectedGroup.getLength(),
|
||||||
|
group.getLength()))
|
||||||
|
.countAssert();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,13 +205,20 @@ public final class TestRunner {
|
|||||||
if (exampleMember.isLocalOrExternalOrHidden()) {
|
if (exampleMember.isLocalOrExternalOrHidden()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exampleName =
|
||||||
|
group.getLength() == 1 ? testName : testName + " #" + exampleIndex;
|
||||||
|
|
||||||
Object exampleValue;
|
Object exampleValue;
|
||||||
try {
|
try {
|
||||||
exampleValue = VmUtils.readMember(group, exampleIndex);
|
exampleValue = VmUtils.readMember(group, exampleIndex);
|
||||||
} catch (VmException err) {
|
} catch (VmException err) {
|
||||||
errored.set(true);
|
errored.set(true);
|
||||||
result.addError(
|
results
|
||||||
new Error(err.getMessage(), err.toPklException(stackFrameTransformer)));
|
.newResult(
|
||||||
|
exampleName,
|
||||||
|
new Error(err.getMessage(), err.toPklException(stackFrameTransformer)))
|
||||||
|
.countAssert();
|
||||||
groupSucceeded.set(false);
|
groupSucceeded.set(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -222,13 +253,18 @@ public final class TestRunner {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
result.addFailure(
|
results
|
||||||
Failure.buildExampleFailure(
|
.newResult(
|
||||||
getDisplayUri(exampleMember),
|
exampleName,
|
||||||
getDisplayUri(expectedMember),
|
Failure.buildExampleFailure(
|
||||||
expectedValuePcf,
|
getDisplayUri(exampleMember),
|
||||||
getDisplayUri(actualMember),
|
getDisplayUri(expectedMember),
|
||||||
exampleValuePcf));
|
expectedValuePcf,
|
||||||
|
getDisplayUri(actualMember),
|
||||||
|
exampleValuePcf))
|
||||||
|
.countAssert();
|
||||||
|
} else {
|
||||||
|
results.newResult(exampleName).countAssert();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -247,12 +283,14 @@ public final class TestRunner {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (examples.getCachedValue(groupKey) == null) {
|
if (examples.getCachedValue(groupKey) == null) {
|
||||||
|
var testName = String.valueOf(groupKey);
|
||||||
allGroupsSucceeded.set(false);
|
allGroupsSucceeded.set(false);
|
||||||
results
|
results
|
||||||
.newResult(String.valueOf(groupKey))
|
.newResult(
|
||||||
.addFailure(
|
testName,
|
||||||
Failure.buildExamplePropertyMismatchFailure(
|
Failure.buildExamplePropertyMismatchFailure(
|
||||||
getDisplayUri(groupMember), String.valueOf(groupKey), false));
|
getDisplayUri(groupMember), testName, false))
|
||||||
|
.countAssert();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -262,10 +300,12 @@ public final class TestRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doRunAndWriteExamples(VmMapping examples, Path outputFile, TestResults results) {
|
private void doRunAndWriteExamples(
|
||||||
|
VmMapping examples, Path outputFile, TestSectionResults results) {
|
||||||
var allSucceeded =
|
var allSucceeded =
|
||||||
examples.forceAndIterateMemberValues(
|
examples.forceAndIterateMemberValues(
|
||||||
(groupKey, groupMember, groupValue) -> {
|
(groupKey, groupMember, groupValue) -> {
|
||||||
|
var testName = String.valueOf(groupKey);
|
||||||
var listing = (VmListing) groupValue;
|
var listing = (VmListing) groupValue;
|
||||||
var success =
|
var success =
|
||||||
listing.iterateMembers(
|
listing.iterateMembers(
|
||||||
@@ -273,22 +313,29 @@ public final class TestRunner {
|
|||||||
if (member.isLocalOrExternalOrHidden()) {
|
if (member.isLocalOrExternalOrHidden()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exampleName =
|
||||||
|
listing.getLength() == 1 ? testName : testName + " #" + idx;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
VmUtils.readMember(listing, idx);
|
VmUtils.readMember(listing, idx);
|
||||||
return true;
|
return true;
|
||||||
} catch (VmException err) {
|
} catch (VmException err) {
|
||||||
results
|
results
|
||||||
.newResult(String.valueOf(groupKey))
|
.newResult(
|
||||||
.addError(
|
exampleName,
|
||||||
new Error(
|
new Error(
|
||||||
err.getMessage(), err.toPklException(stackFrameTransformer)));
|
err.getMessage(), err.toPklException(stackFrameTransformer)))
|
||||||
|
.countAssert();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
results.newResult(String.valueOf(groupKey)).setExampleWritten(true);
|
var result = results.newResult(testName);
|
||||||
|
result.countAssert();
|
||||||
|
result.setExampleWritten(true);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (allSucceeded) {
|
if (allSucceeded) {
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ import org.pkl.core.ast.member.ObjectMember;
|
|||||||
import org.pkl.core.runtime.BaseModule;
|
import org.pkl.core.runtime.BaseModule;
|
||||||
import org.pkl.core.runtime.Identifier;
|
import org.pkl.core.runtime.Identifier;
|
||||||
import org.pkl.core.runtime.TestResults;
|
import org.pkl.core.runtime.TestResults;
|
||||||
import org.pkl.core.runtime.TestResults.TestResult;
|
import org.pkl.core.runtime.TestResults.TestSectionResults;
|
||||||
|
import org.pkl.core.runtime.TestResults.TestSectionResults.Error;
|
||||||
|
import org.pkl.core.runtime.TestResults.TestSectionResults.TestResult;
|
||||||
import org.pkl.core.runtime.VmDynamic;
|
import org.pkl.core.runtime.VmDynamic;
|
||||||
import org.pkl.core.runtime.VmMapping;
|
import org.pkl.core.runtime.VmMapping;
|
||||||
import org.pkl.core.runtime.VmTyped;
|
import org.pkl.core.runtime.VmTyped;
|
||||||
@@ -41,25 +43,45 @@ public final class JUnitReport implements TestReport {
|
|||||||
writer.append(renderXML(" ", "1.0", buildSuite(results)));
|
writer.append(renderXML(" ", "1.0", buildSuite(results)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private VmDynamic buildSuite(TestResults res) {
|
private VmDynamic buildSuite(TestResults results) {
|
||||||
var testCases = testCases(res);
|
var testCases = testCases(results.moduleName, results.facts);
|
||||||
if (!res.getErr().isBlank()) {
|
testCases.addAll(testCases(results.moduleName, results.examples));
|
||||||
|
|
||||||
|
if (!results.getErr().isBlank()) {
|
||||||
var err =
|
var err =
|
||||||
buildXmlElement(
|
buildXmlElement(
|
||||||
"system-err",
|
"system-err",
|
||||||
VmMapping.empty(),
|
VmMapping.empty(),
|
||||||
members -> members.put("body", syntheticElement(makeCdata(res.getErr()))));
|
members -> members.put("body", syntheticElement(makeCdata(results.getErr()))));
|
||||||
testCases.add(err);
|
testCases.add(err);
|
||||||
}
|
}
|
||||||
return buildXmlElement(
|
|
||||||
"testsuite", buildRootAttributes(res), testCases.toArray(new VmDynamic[0]));
|
var attrs =
|
||||||
|
buildAttributes(
|
||||||
|
"name", results.moduleName,
|
||||||
|
"tests", (long) results.totalTests(),
|
||||||
|
"failures", (long) results.totalFailures());
|
||||||
|
|
||||||
|
return buildXmlElement("testsuite", attrs, testCases.toArray(new VmDynamic[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<VmDynamic> testCases(TestResults results) {
|
private ArrayList<VmDynamic> testCases(String moduleName, TestSectionResults testSectionResults) {
|
||||||
var className = results.getModuleName();
|
var elements = new ArrayList<VmDynamic>(testSectionResults.totalTests());
|
||||||
var elements = new ArrayList<VmDynamic>(results.totalTests());
|
|
||||||
for (var res : results.getResults()) {
|
if (testSectionResults.hasError()) {
|
||||||
var attrs = buildAttributes("classname", className, "name", res.getName());
|
var error = error(testSectionResults.getError());
|
||||||
|
|
||||||
|
var attrs =
|
||||||
|
buildAttributes("classname", moduleName + "." + testSectionResults.name, "name", "error");
|
||||||
|
var element = buildXmlElement("testcase", attrs, error.toArray(new VmDynamic[0]));
|
||||||
|
|
||||||
|
elements.add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var res : testSectionResults.getResults()) {
|
||||||
|
var attrs =
|
||||||
|
buildAttributes(
|
||||||
|
"classname", moduleName + "." + testSectionResults.name, "name", res.name);
|
||||||
var failures = failures(res);
|
var failures = failures(res);
|
||||||
failures.addAll(errors(res));
|
failures.addAll(errors(res));
|
||||||
var element = buildXmlElement("testcase", attrs, failures.toArray(new VmDynamic[0]));
|
var element = buildXmlElement("testcase", attrs, failures.toArray(new VmDynamic[0]));
|
||||||
@@ -99,6 +121,17 @@ public final class JUnitReport implements TestReport {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ArrayList<VmDynamic> error(Error error) {
|
||||||
|
var list = new ArrayList<VmDynamic>();
|
||||||
|
var attrs = buildAttributes("message", error.getMessage());
|
||||||
|
list.add(
|
||||||
|
buildXmlElement(
|
||||||
|
"error",
|
||||||
|
attrs,
|
||||||
|
members -> members.put(1, syntheticElement("\n" + error.getRendered()))));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
private VmDynamic buildXmlElement(String name, VmMapping attributes, VmDynamic... elements) {
|
private VmDynamic buildXmlElement(String name, VmMapping attributes, VmDynamic... elements) {
|
||||||
return buildXmlElement(
|
return buildXmlElement(
|
||||||
name,
|
name,
|
||||||
@@ -130,16 +163,6 @@ public final class JUnitReport implements TestReport {
|
|||||||
members.size() - 4);
|
members.size() - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
private VmMapping buildRootAttributes(TestResults results) {
|
|
||||||
return buildAttributes(
|
|
||||||
"name",
|
|
||||||
results.getModuleName(),
|
|
||||||
"tests",
|
|
||||||
(long) results.totalTests(),
|
|
||||||
"failures",
|
|
||||||
(long) results.totalFailures());
|
|
||||||
}
|
|
||||||
|
|
||||||
private VmMapping buildAttributes(Object... attributes) {
|
private VmMapping buildAttributes(Object... attributes) {
|
||||||
EconomicMap<Object, ObjectMember> attrs = EconomicMaps.create(attributes.length);
|
EconomicMap<Object, ObjectMember> attrs = EconomicMaps.create(attributes.length);
|
||||||
for (int i = 0; i < attributes.length; i += 2) {
|
for (int i = 0; i < attributes.length; i += 2) {
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import java.io.IOException;
|
|||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.pkl.core.runtime.TestResults;
|
import org.pkl.core.runtime.TestResults;
|
||||||
import org.pkl.core.runtime.TestResults.Failure;
|
import org.pkl.core.runtime.TestResults.TestSectionResults;
|
||||||
import org.pkl.core.runtime.TestResults.TestResult;
|
import org.pkl.core.runtime.TestResults.TestSectionResults.TestResult;
|
||||||
import org.pkl.core.util.StringUtils;
|
import org.pkl.core.util.StringUtils;
|
||||||
|
|
||||||
public final class SimpleReport implements TestReport {
|
public final class SimpleReport implements TestReport {
|
||||||
@@ -28,38 +28,66 @@ public final class SimpleReport implements TestReport {
|
|||||||
@Override
|
@Override
|
||||||
public void report(TestResults results, Writer writer) throws IOException {
|
public void report(TestResults results, Writer writer) throws IOException {
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
builder.append("module ");
|
|
||||||
builder.append(results.getModuleName());
|
builder.append("module ").append(results.moduleName).append("\n");
|
||||||
builder.append(" (").append(results.getDisplayUri()).append(")\n");
|
|
||||||
StringUtils.joinToStringBuilder(
|
reportResults(results.facts, builder);
|
||||||
builder, results.getResults(), "\n", res -> reportResult(res, builder));
|
reportResults(results.examples, builder);
|
||||||
|
|
||||||
|
builder.append(results.failed() ? "❌ " : "✅ ");
|
||||||
|
|
||||||
|
var totalStatsLine =
|
||||||
|
makeStatsLine("tests", results.totalTests(), results.totalFailures(), results.failed());
|
||||||
|
builder.append(totalStatsLine);
|
||||||
|
|
||||||
|
var totalAssertsStatsLine =
|
||||||
|
makeStatsLine(
|
||||||
|
"asserts", results.totalAsserts(), results.totalAssertsFailed(), results.failed());
|
||||||
|
builder.append(", ").append(totalAssertsStatsLine);
|
||||||
|
|
||||||
builder.append("\n");
|
builder.append("\n");
|
||||||
|
|
||||||
writer.append(builder);
|
writer.append(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reportResult(TestResult result, StringBuilder builder) {
|
private void reportResults(TestSectionResults section, StringBuilder builder) {
|
||||||
builder.append(" ").append(result.getName());
|
if (!section.getResults().isEmpty()) {
|
||||||
if (result.isExampleWritten()) {
|
builder.append(" ").append(section.name).append("\n");
|
||||||
builder.append(" ✍️");
|
|
||||||
} else if (result.isSuccess()) {
|
|
||||||
builder.append(" ✅");
|
|
||||||
} else {
|
|
||||||
builder.append(" ❌\n");
|
|
||||||
StringUtils.joinToStringBuilder(
|
StringUtils.joinToStringBuilder(
|
||||||
builder, result.getFailures(), "\n", failure -> reportFailure(failure, builder));
|
builder, section.getResults(), "\n", res -> reportResult(res, builder));
|
||||||
StringUtils.joinToStringBuilder(
|
builder.append("\n");
|
||||||
builder,
|
} else if (section.hasError()) {
|
||||||
result.getErrors(),
|
builder.append(" ").append(section.name).append("\n");
|
||||||
"\n",
|
var error = section.getError().getRendered();
|
||||||
error -> {
|
appendPadded(builder, error, " ");
|
||||||
builder.append(" Error:\n");
|
builder.append("\n");
|
||||||
appendPadded(builder, error.getException().getMessage(), " ");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void reportFailure(Failure failure, StringBuilder builder) {
|
private void reportResult(TestResult result, StringBuilder builder) {
|
||||||
appendPadded(builder, failure.getRendered(), " ");
|
builder.append(" ");
|
||||||
|
|
||||||
|
if (result.isExampleWritten()) {
|
||||||
|
builder.append(result.name).append(" ✍️");
|
||||||
|
} else {
|
||||||
|
builder.append(result.isFailure() ? "❌ " : "✅ ").append(result.name);
|
||||||
|
|
||||||
|
if (result.isFailure()) {
|
||||||
|
var failurePadding = " ";
|
||||||
|
builder.append("\n");
|
||||||
|
StringUtils.joinToStringBuilder(
|
||||||
|
builder,
|
||||||
|
result.getFailures(),
|
||||||
|
"\n",
|
||||||
|
failure -> appendPadded(builder, failure.getRendered(), failurePadding));
|
||||||
|
StringUtils.joinToStringBuilder(
|
||||||
|
builder,
|
||||||
|
result.getErrors(),
|
||||||
|
"\n",
|
||||||
|
error -> appendPadded(builder, error.getException().getMessage(), failurePadding));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void appendPadded(StringBuilder builder, String lines, String padding) {
|
private static void appendPadded(StringBuilder builder, String lines, String padding) {
|
||||||
@@ -67,6 +95,23 @@ public final class SimpleReport implements TestReport {
|
|||||||
builder,
|
builder,
|
||||||
lines.lines().collect(Collectors.toList()),
|
lines.lines().collect(Collectors.toList()),
|
||||||
"\n",
|
"\n",
|
||||||
str -> builder.append(padding).append(str));
|
str -> {
|
||||||
|
if (str.length() > 0) builder.append(padding).append(str);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String makeStatsLine(String kind, int total, int failed, boolean isFailed) {
|
||||||
|
var passed = total - failed;
|
||||||
|
var pct_passed = total > 0 ? 100.0 * passed / total : 0.0;
|
||||||
|
|
||||||
|
String line = String.format("%.1f%% %s pass", pct_passed, kind);
|
||||||
|
|
||||||
|
if (isFailed) {
|
||||||
|
line += String.format(" [%d/%d failed]", failed, total);
|
||||||
|
} else {
|
||||||
|
line += String.format(" [%d passed]", passed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class EvaluateTestsTest {
|
|||||||
assertThat(results.displayUri).isEqualTo("repl:text")
|
assertThat(results.displayUri).isEqualTo("repl:text")
|
||||||
assertThat(results.totalTests()).isEqualTo(1)
|
assertThat(results.totalTests()).isEqualTo(1)
|
||||||
assertThat(results.failed()).isFalse
|
assertThat(results.failed()).isFalse
|
||||||
assertThat(results.results[0].name).isEqualTo("should pass")
|
assertThat(results.facts.results[0].name).isEqualTo("should pass")
|
||||||
assertThat(results.err.isBlank()).isTrue
|
assertThat(results.err.isBlank()).isTrue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,18 +79,19 @@ class EvaluateTestsTest {
|
|||||||
)
|
)
|
||||||
|
|
||||||
assertThat(results.totalTests()).isEqualTo(1)
|
assertThat(results.totalTests()).isEqualTo(1)
|
||||||
assertThat(results.totalFailures()).isEqualTo(2)
|
assertThat(results.totalFailures()).isEqualTo(1)
|
||||||
assertThat(results.failed()).isTrue
|
assertThat(results.failed()).isTrue
|
||||||
|
|
||||||
val res = results.results[0]
|
val res = results.facts.results[0]
|
||||||
assertThat(res.name).isEqualTo("should fail")
|
assertThat(res.name).isEqualTo("should fail")
|
||||||
assertThat(res.errors).isEmpty()
|
assertThat(results.facts.hasError()).isFalse
|
||||||
|
assertThat(res.failures.size).isEqualTo(2)
|
||||||
|
|
||||||
val fail1 = res.failures[0]
|
val fail1 = res.failures[0]
|
||||||
assertThat(fail1.rendered).isEqualTo("1 == 2 ❌ (repl:text)")
|
assertThat(fail1.rendered).isEqualTo("1 == 2 (repl:text)")
|
||||||
|
|
||||||
val fail2 = res.failures[1]
|
val fail2 = res.failures[1]
|
||||||
assertThat(fail2.rendered).isEqualTo(""""foo" == "bar" ❌ (repl:text)""")
|
assertThat(fail2.rendered).isEqualTo(""""foo" == "bar" (repl:text)""")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -117,7 +118,7 @@ class EvaluateTestsTest {
|
|||||||
assertThat(results.totalFailures()).isEqualTo(1)
|
assertThat(results.totalFailures()).isEqualTo(1)
|
||||||
assertThat(results.failed()).isTrue
|
assertThat(results.failed()).isTrue
|
||||||
|
|
||||||
val res = results.results[0]
|
val res = results.facts.results[0]
|
||||||
assertThat(res.name).isEqualTo("should fail")
|
assertThat(res.name).isEqualTo("should fail")
|
||||||
assertThat(res.failures).hasSize(1)
|
assertThat(res.failures).hasSize(1)
|
||||||
assertThat(res.errors).hasSize(1)
|
assertThat(res.errors).hasSize(1)
|
||||||
@@ -179,7 +180,121 @@ class EvaluateTestsTest {
|
|||||||
assertThat(results.displayUri).startsWith("file:///").endsWith(".pkl")
|
assertThat(results.displayUri).startsWith("file:///").endsWith(".pkl")
|
||||||
assertThat(results.totalTests()).isEqualTo(1)
|
assertThat(results.totalTests()).isEqualTo(1)
|
||||||
assertThat(results.failed()).isFalse
|
assertThat(results.failed()).isFalse
|
||||||
assertThat(results.results[0].name).isEqualTo("user")
|
assertThat(results.examples.results[0].name).isEqualTo("user")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test fact failures with successful example`(@TempDir tempDir: Path) {
|
||||||
|
val file = tempDir.createTempFile(prefix = "example", suffix = ".pkl")
|
||||||
|
Files.writeString(
|
||||||
|
file,
|
||||||
|
"""
|
||||||
|
amends "pkl:test"
|
||||||
|
|
||||||
|
facts {
|
||||||
|
["should fail"] {
|
||||||
|
1 == 2
|
||||||
|
"foo" == "bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
examples {
|
||||||
|
["user"] {
|
||||||
|
new {
|
||||||
|
name = "Bob"
|
||||||
|
age = 33
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
Files.writeString(
|
||||||
|
createExpected(file),
|
||||||
|
"""
|
||||||
|
examples {
|
||||||
|
["user"] {
|
||||||
|
new {
|
||||||
|
name = "Bob"
|
||||||
|
age = 33
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
val results = evaluator.evaluateTest(path(file), false)
|
||||||
|
assertThat(results.moduleName).startsWith("example")
|
||||||
|
assertThat(results.displayUri).startsWith("file:///").endsWith(".pkl")
|
||||||
|
assertThat(results.totalTests()).isEqualTo(2)
|
||||||
|
assertThat(results.totalFailures()).isEqualTo(1)
|
||||||
|
assertThat(results.failed()).isTrue
|
||||||
|
|
||||||
|
assertThat(results.facts.results[0].name).isEqualTo("should fail")
|
||||||
|
assertThat(results.facts.results[0].failures.size).isEqualTo(2)
|
||||||
|
assertThat(results.examples.results[0].name).isEqualTo("user")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test fact error with successful example`(@TempDir tempDir: Path) {
|
||||||
|
val file = tempDir.createTempFile(prefix = "example", suffix = ".pkl")
|
||||||
|
Files.writeString(
|
||||||
|
file,
|
||||||
|
"""
|
||||||
|
amends "pkl:test"
|
||||||
|
|
||||||
|
facts {
|
||||||
|
["should fail"] {
|
||||||
|
throw("exception")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
examples {
|
||||||
|
["user"] {
|
||||||
|
new {
|
||||||
|
name = "Bob"
|
||||||
|
age = 33
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
Files.writeString(
|
||||||
|
createExpected(file),
|
||||||
|
"""
|
||||||
|
examples {
|
||||||
|
["user"] {
|
||||||
|
new {
|
||||||
|
name = "Bob"
|
||||||
|
age = 33
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
val results = evaluator.evaluateTest(path(file), false)
|
||||||
|
assertThat(results.moduleName).startsWith("example")
|
||||||
|
assertThat(results.displayUri).startsWith("file:///").endsWith(".pkl")
|
||||||
|
|
||||||
|
assertThat(results.totalTests()).isEqualTo(2)
|
||||||
|
assertThat(results.totalFailures()).isEqualTo(1)
|
||||||
|
assertThat(results.failed()).isTrue
|
||||||
|
|
||||||
|
val res = results.facts.results[0]
|
||||||
|
assertThat(res.name).isEqualTo("should fail")
|
||||||
|
assertThat(res.failures).hasSize(0)
|
||||||
|
assertThat(res.errors).hasSize(1)
|
||||||
|
|
||||||
|
val error = res.errors[0]
|
||||||
|
assertThat(error.message).isEqualTo("exception")
|
||||||
|
|
||||||
|
assertThat(results.examples.results[0].name).isEqualTo("user")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -224,9 +339,9 @@ class EvaluateTestsTest {
|
|||||||
assertThat(results.failed()).isTrue
|
assertThat(results.failed()).isTrue
|
||||||
assertThat(results.totalFailures()).isEqualTo(1)
|
assertThat(results.totalFailures()).isEqualTo(1)
|
||||||
|
|
||||||
val res = results.results[0]
|
val res = results.examples.results[0]
|
||||||
assertThat(res.name).isEqualTo("user")
|
assertThat(res.name).isEqualTo("user")
|
||||||
assertThat(res.errors.isEmpty()).isTrue
|
assertFalse(results.examples.hasError())
|
||||||
|
|
||||||
val fail1 = res.failures[0]
|
val fail1 = res.failures[0]
|
||||||
assertThat(fail1.rendered.stripFileAndLines(tempDir))
|
assertThat(fail1.rendered.stripFileAndLines(tempDir))
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class TestsTest : AbstractTest() {
|
|||||||
writePklFile()
|
writePklFile()
|
||||||
|
|
||||||
val res = runTask("evalTest")
|
val res = runTask("evalTest")
|
||||||
assertThat(res.output).contains("should pass ✅")
|
assertThat(res.output).contains("✅ should pass")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -49,9 +49,9 @@ class TestsTest : AbstractTest() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val res = runTask("evalTest", expectFailure = true)
|
val res = runTask("evalTest", expectFailure = true)
|
||||||
assertThat(res.output).contains("should fail ❌")
|
assertThat(res.output).contains("❌ should fail")
|
||||||
assertThat(res.output).contains("1 == 3 ❌")
|
assertThat(res.output).contains("1 == 3")
|
||||||
assertThat(res.output).contains(""""foo" == "bar" ❌""")
|
assertThat(res.output).contains(""""foo" == "bar"""")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -68,22 +68,28 @@ class TestsTest : AbstractTest() {
|
|||||||
.trimIndent()
|
.trimIndent()
|
||||||
)
|
)
|
||||||
|
|
||||||
val output = runTask("evalTest", expectFailure = true).output.stripFilesAndLines()
|
val output =
|
||||||
|
runTask("evalTest", expectFailure = true)
|
||||||
|
.output
|
||||||
|
.stripFilesAndLines()
|
||||||
|
.lineSequence()
|
||||||
|
.joinToString("\n")
|
||||||
|
|
||||||
assertThat(output)
|
assertThat(output)
|
||||||
.containsIgnoringNewLines(
|
.containsIgnoringNewLines(
|
||||||
"""
|
"""
|
||||||
> Task :evalTest FAILED
|
> Task :evalTest FAILED
|
||||||
module test (file:///file, line x)
|
module test
|
||||||
should pass ✅
|
facts
|
||||||
error ❌
|
✅ should pass
|
||||||
Error:
|
❌ error
|
||||||
–– Pkl Error ––
|
–– Pkl Error ––
|
||||||
exception
|
exception
|
||||||
|
|
||||||
9 | throw("exception")
|
9 | throw("exception")
|
||||||
^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
at test#facts["error"][#1] (file:///file, line x)
|
at test#facts["error"][#1] (file:///file, line x)
|
||||||
|
❌ 50.0% tests pass [1/2 failed], 66.7% asserts pass [1/3 failed]
|
||||||
"""
|
"""
|
||||||
.trimIndent()
|
.trimIndent()
|
||||||
)
|
)
|
||||||
@@ -96,41 +102,41 @@ class TestsTest : AbstractTest() {
|
|||||||
|
|
||||||
writeBuildFile()
|
writeBuildFile()
|
||||||
|
|
||||||
val output = runTask("evalTest", expectFailure = true).output.stripFilesAndLines()
|
val output =
|
||||||
|
runTask("evalTest", expectFailure = true)
|
||||||
|
.output
|
||||||
|
.stripFilesAndLines()
|
||||||
|
.lineSequence()
|
||||||
|
.joinToString("\n")
|
||||||
|
|
||||||
assertThat(output.trimStart())
|
assertThat(output.trimStart())
|
||||||
.contains(
|
.startsWith(
|
||||||
"""
|
"""
|
||||||
module test (file:///file, line x)
|
> Task :evalTest FAILED
|
||||||
sum numbers ✅
|
pkl: TRACE: 8 = 8 (file:///file, line x)
|
||||||
divide numbers ✅
|
module test
|
||||||
fail ❌
|
facts
|
||||||
4 == 9 ❌ (file:///file, line x)
|
✅ sum numbers
|
||||||
"foo" == "bar" ❌ (file:///file, line x)
|
✅ divide numbers
|
||||||
user 0 ✅
|
❌ fail
|
||||||
user 1 ❌
|
4 == 9 (file:///file, line x)
|
||||||
(file:///file, line x)
|
"foo" == "bar" (file:///file, line x)
|
||||||
Expected: (file:///file, line x)
|
examples
|
||||||
new {
|
✅ user 0
|
||||||
name = "Pigeon"
|
✅ user 1 #0
|
||||||
age = 40
|
❌ user 1 #1
|
||||||
}
|
(file:///file, line x)
|
||||||
Actual: (file:///file, line x)
|
Expected: (file:///file, line x)
|
||||||
new {
|
new {
|
||||||
name = "Pigeon"
|
name = "Parrot"
|
||||||
age = 41
|
age = 35
|
||||||
}
|
}
|
||||||
(file:///file, line x)
|
Actual: (file:///file, line x)
|
||||||
Expected: (file:///file, line x)
|
new {
|
||||||
new {
|
name = "Welma"
|
||||||
name = "Parrot"
|
age = 35
|
||||||
age = 35
|
}
|
||||||
}
|
❌ 66.7% tests pass [2/6 failed], 66.7% asserts pass [3/9 failed]
|
||||||
Actual: (file:///file, line x)
|
|
||||||
new {
|
|
||||||
name = "Welma"
|
|
||||||
age = 35
|
|
||||||
}
|
|
||||||
"""
|
"""
|
||||||
.trimIndent()
|
.trimIndent()
|
||||||
)
|
)
|
||||||
@@ -138,28 +144,7 @@ class TestsTest : AbstractTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `overwrite expected examples`() {
|
fun `overwrite expected examples`() {
|
||||||
writePklFile(
|
writePklFile(additionalExamples = examples)
|
||||||
additionalExamples =
|
|
||||||
"""
|
|
||||||
["user 0"] {
|
|
||||||
new {
|
|
||||||
name = "Cool"
|
|
||||||
age = 11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
["user 1"] {
|
|
||||||
new {
|
|
||||||
name = "Pigeon"
|
|
||||||
age = 41
|
|
||||||
}
|
|
||||||
new {
|
|
||||||
name = "Welma"
|
|
||||||
age = 35
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
.trimIndent()
|
|
||||||
)
|
|
||||||
writeFile("test.pkl-expected.pcf", bigTestExpected)
|
writeFile("test.pkl-expected.pcf", bigTestExpected)
|
||||||
|
|
||||||
writeBuildFile("overwrite = true")
|
writeBuildFile("overwrite = true")
|
||||||
@@ -170,6 +155,64 @@ class TestsTest : AbstractTest() {
|
|||||||
assertThat(output).contains("user 1 ✍️")
|
assertThat(output).contains("user 1 ✍️")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `full example with error`() {
|
||||||
|
writeBuildFile()
|
||||||
|
|
||||||
|
writePklFile(
|
||||||
|
additionalFacts =
|
||||||
|
"""
|
||||||
|
["error"] {
|
||||||
|
throw("exception")
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
additionalExamples = examples
|
||||||
|
)
|
||||||
|
writeFile("test.pkl-expected.pcf", bigTestExpected)
|
||||||
|
|
||||||
|
val output =
|
||||||
|
runTask("evalTest", expectFailure = true)
|
||||||
|
.output
|
||||||
|
.stripFilesAndLines()
|
||||||
|
.lineSequence()
|
||||||
|
.joinToString("\n")
|
||||||
|
|
||||||
|
assertThat(output.trimStart())
|
||||||
|
.startsWith(
|
||||||
|
"""
|
||||||
|
> Task :evalTest FAILED
|
||||||
|
module test
|
||||||
|
facts
|
||||||
|
✅ should pass
|
||||||
|
❌ error
|
||||||
|
–– Pkl Error ––
|
||||||
|
exception
|
||||||
|
|
||||||
|
9 | throw("exception")
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
at test#facts["error"][#1] (file:///file, line x)
|
||||||
|
examples
|
||||||
|
✅ user 0
|
||||||
|
✅ user 1 #0
|
||||||
|
❌ user 1 #1
|
||||||
|
(file:///file, line x)
|
||||||
|
Expected: (file:///file, line x)
|
||||||
|
new {
|
||||||
|
name = "Parrot"
|
||||||
|
age = 35
|
||||||
|
}
|
||||||
|
Actual: (file:///file, line x)
|
||||||
|
new {
|
||||||
|
name = "Welma"
|
||||||
|
age = 35
|
||||||
|
}
|
||||||
|
❌ 60.0% tests pass [2/5 failed], 66.7% asserts pass [2/6 failed]
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `JUnit reports`() {
|
fun `JUnit reports`() {
|
||||||
val pklFile = writePklFile(contents = bigTest)
|
val pklFile = writePklFile(contents = bigTest)
|
||||||
@@ -186,26 +229,16 @@ class TestsTest : AbstractTest() {
|
|||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
"""
|
"""
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<testsuite name="test" tests="5" failures="4">
|
<testsuite name="test" tests="6" failures="2">
|
||||||
<testcase classname="test" name="sum numbers"></testcase>
|
<testcase classname="test.facts" name="sum numbers"></testcase>
|
||||||
<testcase classname="test" name="divide numbers"></testcase>
|
<testcase classname="test.facts" name="divide numbers"></testcase>
|
||||||
<testcase classname="test" name="fail">
|
<testcase classname="test.facts" name="fail">
|
||||||
<failure message="Fact Failure">4 == 9 ❌ (file:///file, line x)</failure>
|
<failure message="Fact Failure">4 == 9 (file:///file, line x)</failure>
|
||||||
<failure message="Fact Failure">"foo" == "bar" ❌ (file:///file, line x)</failure>
|
<failure message="Fact Failure">"foo" == "bar" (file:///file, line x)</failure>
|
||||||
</testcase>
|
</testcase>
|
||||||
<testcase classname="test" name="user 0"></testcase>
|
<testcase classname="test.examples" name="user 0"></testcase>
|
||||||
<testcase classname="test" name="user 1">
|
<testcase classname="test.examples" name="user 1 #0"></testcase>
|
||||||
<failure message="Example Failure">(file:///file, line x)
|
<testcase classname="test.examples" name="user 1 #1">
|
||||||
Expected: (file:///file, line x)
|
|
||||||
new {
|
|
||||||
name = "Pigeon"
|
|
||||||
age = 40
|
|
||||||
}
|
|
||||||
Actual: (file:///file, line x)
|
|
||||||
new {
|
|
||||||
name = "Pigeon"
|
|
||||||
age = 41
|
|
||||||
}</failure>
|
|
||||||
<failure message="Example Failure">(file:///file, line x)
|
<failure message="Example Failure">(file:///file, line x)
|
||||||
Expected: (file:///file, line x)
|
Expected: (file:///file, line x)
|
||||||
new {
|
new {
|
||||||
@@ -227,6 +260,86 @@ class TestsTest : AbstractTest() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `JUnit reports with error`() {
|
||||||
|
val pklFile =
|
||||||
|
writePklFile(
|
||||||
|
additionalFacts =
|
||||||
|
"""
|
||||||
|
["error"] {
|
||||||
|
throw("exception")
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
additionalExamples = examples
|
||||||
|
)
|
||||||
|
writeFile("test.pkl-expected.pcf", bigTestExpected)
|
||||||
|
|
||||||
|
writeBuildFile("junitReportsDir = file('${pklFile.parent.toNormalizedPathString()}/build')")
|
||||||
|
|
||||||
|
runTask("evalTest", expectFailure = true)
|
||||||
|
|
||||||
|
val outputFile = testProjectDir.resolve("build/test.xml")
|
||||||
|
val report = outputFile.readText().stripFilesAndLines()
|
||||||
|
|
||||||
|
assertThat(report)
|
||||||
|
.isEqualTo(
|
||||||
|
"""
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<testsuite name="test" tests="5" failures="2">
|
||||||
|
<testcase classname="test.facts" name="should pass"></testcase>
|
||||||
|
<testcase classname="test.facts" name="error">
|
||||||
|
<error message="exception">–– Pkl Error ––
|
||||||
|
exception
|
||||||
|
|
||||||
|
9 | throw("exception")
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
at test#facts["error"][#1] (file:///file, line x)
|
||||||
|
</error>
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="test.examples" name="user 0"></testcase>
|
||||||
|
<testcase classname="test.examples" name="user 1 #0"></testcase>
|
||||||
|
<testcase classname="test.examples" name="user 1 #1">
|
||||||
|
<failure message="Example Failure">(file:///file, line x)
|
||||||
|
Expected: (file:///file, line x)
|
||||||
|
new {
|
||||||
|
name = "Parrot"
|
||||||
|
age = 35
|
||||||
|
}
|
||||||
|
Actual: (file:///file, line x)
|
||||||
|
new {
|
||||||
|
name = "Welma"
|
||||||
|
age = 35
|
||||||
|
}</failure>
|
||||||
|
</testcase>
|
||||||
|
</testsuite>
|
||||||
|
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val examples =
|
||||||
|
"""
|
||||||
|
["user 0"] {
|
||||||
|
new {
|
||||||
|
name = "Cool"
|
||||||
|
age = 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
["user 1"] {
|
||||||
|
new {
|
||||||
|
name = "Pigeon"
|
||||||
|
age = 40
|
||||||
|
}
|
||||||
|
new {
|
||||||
|
name = "Welma"
|
||||||
|
age = 35
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
|
||||||
private val bigTest =
|
private val bigTest =
|
||||||
"""
|
"""
|
||||||
amends "pkl:test"
|
amends "pkl:test"
|
||||||
@@ -249,22 +362,7 @@ class TestsTest : AbstractTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
examples {
|
examples {
|
||||||
["user 0"] {
|
$examples
|
||||||
new {
|
|
||||||
name = "Cool"
|
|
||||||
age = 11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
["user 1"] {
|
|
||||||
new {
|
|
||||||
name = "Pigeon"
|
|
||||||
age = 41
|
|
||||||
}
|
|
||||||
new {
|
|
||||||
name = "Welma"
|
|
||||||
age = 35
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
.trimIndent()
|
.trimIndent()
|
||||||
|
|||||||
Reference in New Issue
Block a user