Skip to content

Commit

Permalink
Merge pull request #125 from olafurpg/stack-traces
Browse files Browse the repository at this point in the history
  • Loading branch information
olafurpg authored May 10, 2020
2 parents 6476e67 + a2a694e commit e038fe1
Show file tree
Hide file tree
Showing 29 changed files with 309 additions and 52 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ inThisBuild(
resolvers += Resolver.sonatypeRepo("public"),
useSuperShell := false,
scalacOptions ++= List(
"-target:jvm-1.8",
"-language:implicitConversions"
)
)
Expand Down
13 changes: 13 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ id: troubleshooting
title: Troubleshooting
---

## Print full stack traces

By default, MUnit trims exception stack traces to avoid printing redundant
information to the console. Use the `-F` test framework flag to print full stack
traces, which can be helpful when debugging a cryptic error.

In sbt, test framework flags can be passed to the `testOnly` task.

```sh
$ sbt
> myproject/testOnly -- -F
```

## Invalid test class

If you define a test suite as an `object` instead of `class` you get the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package munit.internal.junitinterface;

public interface Configurable {
public void configure(Settings settings);
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ public void testFailure(final Failure failure)
trimStackTrace(
failure.getException(),
"java.lang.Thread",
failure.getDescription().getClassName()
failure.getDescription().getClassName(),
settings
);
} catch (Throwable t) {
// Ignore error.
Expand Down Expand Up @@ -227,7 +228,8 @@ void uncapture(boolean replay)


// Removes stack trace elements that reference the reflective invocation in TestLauncher.
private static void trimStackTrace(Throwable ex, String fromClassName, String toClassName) {
private static void trimStackTrace(Throwable ex, String fromClassName, String toClassName, Settings settings) {
if (!settings.trimStackTraces()) return;
Throwable cause = ex;
while (cause != null) {
StackTraceElement[] stackTrace = cause.getStackTrace();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@

public class JUnitComputer extends Computer {
final Map<Class<?>, Class<?>> suiteRunners;
final Settings settings;

public JUnitComputer(ClassLoader testClassLoader, CustomRunners customRunners) {
public JUnitComputer(ClassLoader testClassLoader, CustomRunners customRunners, Settings settings) {
this.settings = settings;
suiteRunners = new HashMap<>();
customRunners.all().forEach((suite, runner) -> {
try {
Expand Down Expand Up @@ -73,6 +75,10 @@ protected Runner getRunner(RunnerBuilder builder, Class<?> testClass) throws Thr
Optional<Class<?>> runnerClass = customRunner(testClass);
if (runnerClass.isPresent()) {
Runner runner = (Runner) runnerClass.get().getConstructor(Class.class).newInstance(testClass);
if (runner instanceof Configurable) {
Configurable configurable = (Configurable) runner;
configurable.configure(this.settings);
}
return new JUnitRunnerWrapper(runner);
} else {
return super.getRunner(builder, testClass);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ final class JUnitRunner implements Runner {
this.remoteArgs = remoteArgs;
this.testClassLoader = testClassLoader;
this.customRunners = customRunners;
Settings defaults = Settings.defaults();

boolean quiet = false, nocolor = false, decodeScalaNames = false,
logAssert = true, logExceptionClass = true, useSbtLoggers = false;
boolean verbose = false;
boolean suppressSystemError = false;
boolean trimStackTraces = defaults.trimStackTraces();
RunSettings.Summary summary = RunSettings.Summary.SBT;
HashMap<String, String> sysprops = new HashMap<String, String>();
ArrayList<String> globPatterns = new ArrayList<String>();
Expand All @@ -58,6 +60,8 @@ final class JUnitRunner implements Runner {
else if("-c".equals(s)) logExceptionClass = false;
else if("+l".equals(s)) useSbtLoggers = true;
else if("-l".equals(s)) useSbtLoggers = false;
else if("-F".equals(s)) trimStackTraces = false;
else if("+F".equals(s)) trimStackTraces = true;
else if(s.startsWith("--tests=")) testFilter = s.substring(8);
else if(s.startsWith("--ignore-runners=")) ignoreRunners = s.substring(17);
else if(s.startsWith("--run-listener=")) runListener = s.substring(15);
Expand All @@ -82,7 +86,7 @@ else if(s.startsWith("-D") && s.contains("=")) {
else if("--stderr".equals(s)) suppressSystemError = false;
}
this.settings =
new RunSettings(!nocolor, decodeScalaNames, quiet, verbose, useSbtLoggers, summary, logAssert, ignoreRunners, logExceptionClass,
new RunSettings(!nocolor, decodeScalaNames, quiet, verbose, useSbtLoggers, trimStackTraces, summary, logAssert, ignoreRunners, logExceptionClass,
suppressSystemError, sysprops, globPatterns, includeCategories, excludeCategories, includeTags, excludeTags,
testFilter);
this.runListener = createRunListener(runListener);
Expand All @@ -92,7 +96,7 @@ else if(s.startsWith("-D") && s.contains("=")) {
@Override
public Task[] tasks(TaskDef[] taskDefs) {
used = true;
JUnitComputer computer = new JUnitComputer(testClassLoader, customRunners);
JUnitComputer computer = new JUnitComputer(testClassLoader, customRunners, settings);
int length = taskDefs.length;
List<Task> tasks = new ArrayList<>(taskDefs.length);
for (int i = 0; i < length; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import sbt.testing.Status;

class RunSettings {
class RunSettings implements Settings {
private static final Object NULL = new Object();

final boolean color;
Expand All @@ -30,6 +30,7 @@ class RunSettings {
final boolean logExceptionClass;
final Set<String> includeTags, excludeTags;
final boolean useSbtLoggers;
final boolean trimStackTraces;
final boolean verbose;
final boolean suppressSystemError;
final Summary summary;
Expand All @@ -42,7 +43,8 @@ class RunSettings {
private final HashSet<String> ignoreRunners = new HashSet<String>();

RunSettings(boolean color, boolean decodeScalaNames, boolean quiet,
boolean verbose, boolean useSbtLoggers, Summary summary, boolean logAssert, String ignoreRunners,
boolean verbose, boolean useSbtLoggers, boolean trimStackTraces,
Summary summary, boolean logAssert, String ignoreRunners,
boolean logExceptionClass,
boolean suppressSystemError, HashMap<String, String> sysprops,
ArrayList<String> globPatterns,
Expand All @@ -67,6 +69,7 @@ class RunSettings {
this.excludeCategories = excludeCategories;
this.testFilter = testFilter;
this.useSbtLoggers = useSbtLoggers;
this.trimStackTraces = trimStackTraces;
}

String decodeName(String name) {
Expand Down Expand Up @@ -205,6 +208,11 @@ void restoreSystemProperties(Map<String, Object> oldprops) {
}
}

@Override
public boolean trimStackTraces() {
return this.trimStackTraces;
}

static enum Summary {
SBT, ONE_LINE, LIST_FAILED
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package munit.internal.junitinterface;

public interface Settings {
public boolean trimStackTraces();
public static Settings defaults() {
return new Settings() {
@Override
public boolean trimStackTraces() {
return true;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package munit.internal.junitinterface

trait Configurable {
def configure(settings: Settings): Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ abstract class JUnitFramework extends Framework {
}

private def parseRunSettings(args: Array[String]): RunSettings = {
val defaults = Settings.defaults()
var verbose = false
var noColor = false
var decodeScalaNames = false
var logAssert = false
var notLogExceptionClass = false
var useSbtLoggers = false
var trimStackTraces = defaults.trimStackTraces()
var includeTags = Set.empty[String]
var excludeTags = Set.empty[String]
for (str <- args) {
Expand Down Expand Up @@ -104,6 +106,8 @@ abstract class JUnitFramework extends Framework {
case "+c" => notLogExceptionClass = false
case "+l" => useSbtLoggers = true
case "-l" => useSbtLoggers = false
case "+F" => trimStackTraces = true
case "-F" => trimStackTraces = false
case _ =>
}
}
Expand All @@ -114,6 +118,7 @@ abstract class JUnitFramework extends Framework {
logAssert = logAssert,
notLogExceptionClass = notLogExceptionClass,
useSbtLoggers = useSbtLoggers,
trimStackTraces = trimStackTraces,
tags = new TagsFilter(includeTags, excludeTags)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ final class RunSettings(
val logAssert: Boolean,
val notLogExceptionClass: Boolean,
val useSbtLoggers: Boolean,
val trimStackTraces: Boolean,
val tags: TagsFilter
) {
) extends Settings {
def decodeName(name: String): String = {
if (decodeScalaNames)
Try(scala.reflect.NameTransformer.decode(name)).getOrElse(name)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package munit.internal.junitinterface

trait Settings {
def trimStackTraces(): Boolean
}

object Settings {
def defaults(): Settings = new Settings {
def trimStackTraces(): Boolean = true
}
}
11 changes: 11 additions & 0 deletions munit/shared/src/main/scala/munit/Assertions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ trait Assertions extends MacroCompat.CompileErrorMacro {
munitPrint(clue),
printObtainedAsStripMargin = false
)
// try with `.toString` in case `munitPrint()` produces identical formatting for both values.
Diffs.assertNoDiff(
obtained.toString(),
expected.toString(),
message => fail(message),
munitPrint(clue),
printObtainedAsStripMargin = false
)
fail(
s"values are not equal even if they have the same `toString()`: $obtained"
)
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion munit/shared/src/main/scala/munit/FailException.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ class FailException(

override def fillInStackTrace(): Throwable = {
val result = super.fillInStackTrace()
result.setStackTrace(result.getStackTrace().slice(0, 1))
if (!isStackTracesEnabled) {
result.setStackTrace(result.getStackTrace().slice(0, 1))
}
result
}
}
5 changes: 4 additions & 1 deletion munit/shared/src/main/scala/munit/FunFixtures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ trait FunFixtures { self: FunSuite =>
}

object FunFixture {
def apply[T](setup: TestOptions => T, teardown: T => Unit) = {
def apply[T](
setup: TestOptions => T,
teardown: T => Unit
): FunFixture[T] = {
implicit val ec = munitExecutionContext
async[T](
options => Future { setup(options) },
Expand Down
24 changes: 4 additions & 20 deletions munit/shared/src/main/scala/munit/GenericTest.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package munit

import scala.runtime.Statics
import java.lang.annotation.Annotation
import scala.collection.mutable

Expand Down Expand Up @@ -42,25 +41,10 @@ class GenericTest[T](
new GenericTest(name, body, tags, location)
}
override def toString(): String = s"GenericTest($name, $tags, $location)"
override def equals(obj: Any): Boolean = {
obj.asInstanceOf[AnyRef].eq(this) || (obj match {
case t: GenericTest[_] =>
t.name == name &&
// skip body
t.tags == tags &&
t.location == location
case _ =>
false
})
}
override def hashCode(): Int = {
var acc = -889275714
acc = Statics.mix(acc, Statics.anyHash(name))
// skip body
acc = Statics.mix(acc, Statics.anyHash(tags))
acc = Statics.mix(acc, Statics.anyHash(location))
acc
}
// NOTE(olafur): tests have reference equality because there's no reasonable
// structural equality that we can use to compare the test body function.
override def equals(obj: Any): Boolean = this.eq(obj.asInstanceOf[AnyRef])
override def hashCode(): Int = System.identityHashCode(this)
def annotations: Array[Annotation] = {
val buf = new mutable.ArrayBuffer[Annotation](tags.size + 1)
buf ++= tags
Expand Down
Loading

0 comments on commit e038fe1

Please sign in to comment.