Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display failure reason #22

Merged
merged 6 commits into from
Oct 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,23 @@ The following themes are currently supported:
2. `standard` - displays colours but no Unicode symbols
3. `mocha` - similar to what [mochajs](https://github.com/mochajs/mocha) prints, with colours and Unicode symbols

### Showing exceptions

By default, the `showExceptions` flag is turned on. This shows why the tests failed including the location of the
failure. Of course, you can switch off this slightly more verbose logging by setting `showExceptions` to `false`.

```groovy
testlogger {
showExceptions false
}
```

## FAQ

### Does it work on Windows?

Mostly. The `standard` and `plain` themes work out of the box but you might have to make a few modifications to your system settings to see Unicode
symbols when using the `mocha` theme.
Mostly. The `standard` and `plain` themes work out of the box but you might have to make a few modifications to your
system settings to see Unicode symbols when using the `mocha` theme.

1. Set or update `JAVA_OPTS` with the system property `-Dfile.encoding=UTF-8`
2. Change the terminal code page to 65001 by executing `chcp 65001`
Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies {
exclude module: 'groovy-all'
}
testCompile 'net.bytebuddy:byte-buddy:1.7.5'
testCompile 'org.objenesis:objenesis:2.6'
testCompile 'commons-io:commons-io:2.5'

functionalTestCompile localGroovy()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
package com.adarshr.gradle.testlogger

import com.adarshr.gradle.testlogger.theme.ThemeType
import org.gradle.api.Project

import static com.adarshr.gradle.testlogger.theme.ThemeType.PLAIN
import static com.adarshr.gradle.testlogger.theme.ThemeType.STANDARD
import static org.gradle.api.logging.configuration.ConsoleOutput.Plain

class TestLoggerExtension {

ThemeType theme = STANDARD

/**
* @see org.gradle.api.tasks.testing.logging.TestLogging#getShowExceptions()
*/
boolean showExceptions = true

TestLoggerExtension(Project project) {
this.theme = project.gradle.startParameter.consoleOutput == Plain ? PLAIN : this.theme
}

void setTheme(String theme) {
this.theme = ThemeType.valueOf(theme.toUpperCase())
}

void setTheme(ThemeType theme) {
this.theme = theme
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class TestLoggerPlugin implements Plugin<Project> {

@Override
void apply(Project project) {
project.extensions.create('testlogger', TestLoggerExtension)
project.extensions.create('testlogger', TestLoggerExtension, project)

project.afterEvaluate {
project.tasks.withType(Test).each { test ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
package com.adarshr.gradle.testlogger.logger

import com.adarshr.gradle.testlogger.TestLoggerExtension
import com.adarshr.gradle.testlogger.theme.Theme
import com.adarshr.gradle.testlogger.theme.ThemeFactory
import org.gradle.api.Project
import org.gradle.api.tasks.testing.TestDescriptor
import org.gradle.api.tasks.testing.TestListener
import org.gradle.api.tasks.testing.TestResult

import static com.adarshr.gradle.testlogger.theme.ThemeFactory.loadTheme
import static com.adarshr.gradle.testlogger.theme.ThemeType.PLAIN
import static org.gradle.api.logging.configuration.ConsoleOutput.Plain

class TestEventLogger implements TestListener {

private final boolean plainConsole
private final Theme theme
private final ConsoleLogger logger
private boolean logBeforeSuite

TestEventLogger(Project project) {
logger = new ConsoleLogger(project.logger)
plainConsole = project.gradle.startParameter.consoleOutput == Plain || project.testlogger.theme == PLAIN
theme = plainConsole ? loadTheme(PLAIN) : loadTheme(project.testlogger.theme)
theme = ThemeFactory.getTheme(project.testlogger as TestLoggerExtension)
}

@Override
Expand All @@ -30,7 +26,7 @@ class TestEventLogger implements TestListener {
}

if (logBeforeSuite && suite.className) {
logger.log theme.beforeSuite(suite)
logger.log theme.suiteText(suite)
}
}

Expand All @@ -52,6 +48,6 @@ class TestEventLogger implements TestListener {

@Override
void afterTest(TestDescriptor descriptor, TestResult result) {
logger.log theme.afterTest(descriptor, result)
logger.log theme.testText(descriptor, result)
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,52 @@
package com.adarshr.gradle.testlogger.theme

import com.adarshr.gradle.testlogger.TestLoggerExtension
import org.gradle.api.tasks.testing.TestDescriptor
import org.gradle.api.tasks.testing.TestResult

@SuppressWarnings("GrMethodMayBeStatic")
abstract class AbstractTheme implements Theme {

@SuppressWarnings("GrMethodMayBeStatic")
String escape(String text) {
text.replace('[', '\\[').replace(']', '\\]')
protected final boolean showExceptions

AbstractTheme(TestLoggerExtension extension) {
this.showExceptions = extension.showExceptions
}

@Override
String exceptionText(TestDescriptor descriptor, TestResult result) {
exceptionText(descriptor, result, 2)
}

protected String escape(String text) {
text
.replace('\u001B', '')
.replace('[', '\\[')
.replace(']', '\\]')
}

protected String exceptionText(TestDescriptor descriptor, TestResult result, int indent) {
def line = new StringBuilder()
def indentation = ' ' * indent

if (showExceptions) {
line << '\n\n'

line << result.exception.toString().trim().readLines().collect {
"${indentation}${escape(it)}"
}.join('\n')

line << '\n'

line << result.exception.stackTrace.find {
it.className == descriptor.className
}.collect {
"${indentation} at ${escape(it.toString())}"
}.join('\n')

line << '\n'
}

line
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,44 @@
package com.adarshr.gradle.testlogger.theme

import groovy.transform.InheritConstructors
import org.gradle.api.tasks.testing.TestDescriptor
import org.gradle.api.tasks.testing.TestResult
import org.gradle.api.tasks.testing.TestResult.ResultType

import static org.gradle.api.tasks.testing.TestResult.ResultType.*

@InheritConstructors
class MochaTheme extends AbstractTheme {

@Override
String beforeSuite(TestDescriptor descriptor) {
String suiteText(TestDescriptor descriptor) {
" [bold]${escape(descriptor.className)}[/]\n"
}

@Override
String afterTest(TestDescriptor descriptor, TestResult result) {
String testText(TestDescriptor descriptor, TestResult result) {
def line = new StringBuilder()

switch (result.resultType) {
case SUCCESS: return " [erase-ahead,green]${getSymbol(result.resultType)}[/] ${escape(descriptor.name)}"
case FAILURE: return " [erase-ahead,red]${getSymbol(result.resultType)} ${escape(descriptor.name)}[/]"
case SKIPPED: return " [erase-ahead,yellow]${getSymbol(result.resultType)} ${escape(descriptor.name)}[/]"
default: return ''
case SUCCESS:
line << " [erase-ahead,green]${getSymbol(result.resultType)}[/] ${escape(descriptor.name)}"
break
case FAILURE:
line << " [erase-ahead,red]${getSymbol(result.resultType)} ${escape(descriptor.name)}[/]"
line << exceptionText(descriptor, result)
break
case SKIPPED:
line << " [erase-ahead,yellow]${getSymbol(result.resultType)} ${escape(descriptor.name)}[/]"
break
}

line
}

@Override
String exceptionText(TestDescriptor descriptor, TestResult result) {
def line = super.exceptionText(descriptor, result, 6)
line ? "[red]${line}[/]" : ''
}

private static String getSymbol(ResultType resultType) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.adarshr.gradle.testlogger.theme

import groovy.transform.InheritConstructors
import org.gradle.api.tasks.testing.TestDescriptor
import org.gradle.api.tasks.testing.TestResult

import static org.gradle.api.tasks.testing.TestResult.ResultType.*

@InheritConstructors
class PlainTheme extends AbstractTheme {

private static final Map RESULT_TYPE_MAPPING = [
Expand All @@ -14,12 +16,18 @@ class PlainTheme extends AbstractTheme {
]

@Override
String beforeSuite(TestDescriptor descriptor) {
String suiteText(TestDescriptor descriptor) {
"${escape(descriptor.className)}\n"
}

@Override
String afterTest(TestDescriptor descriptor, TestResult result) {
" Test ${escape(descriptor.name)} ${RESULT_TYPE_MAPPING[result.resultType]}"
String testText(TestDescriptor descriptor, TestResult result) {
def line = new StringBuilder(" Test ${escape(descriptor.name)} ${RESULT_TYPE_MAPPING[result.resultType]}")

if (result.resultType == FAILURE) {
line << exceptionText(descriptor, result)
}

line
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
package com.adarshr.gradle.testlogger.theme

import groovy.transform.InheritConstructors
import org.gradle.api.tasks.testing.TestDescriptor
import org.gradle.api.tasks.testing.TestResult

import static org.gradle.api.tasks.testing.TestResult.ResultType.*

@InheritConstructors
class StandardTheme extends AbstractTheme {

@Override
String beforeSuite(TestDescriptor descriptor) {
String suiteText(TestDescriptor descriptor) {
"[bold,bright-yellow]${escape(descriptor.className)}[/]\n"
}

@Override
String afterTest(TestDescriptor descriptor, TestResult result) {
String testText(TestDescriptor descriptor, TestResult result) {
def line = new StringBuilder("[bold] Test [/]${escape(descriptor.name)}")

switch (result.resultType) {
case SUCCESS: line << '[erase-ahead,green] PASSED'; break
case FAILURE: line << '[erase-ahead,red] FAILED'; break
case SKIPPED: line << '[erase-ahead,yellow] SKIPPED'; break
case SUCCESS:
line << '[erase-ahead,green] PASSED'
break
case FAILURE:
line << '[erase-ahead,red] FAILED'
line << exceptionText(descriptor, result)
break
case SKIPPED:
line << '[erase-ahead,yellow] SKIPPED'
break
}

line << '[/]'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import org.gradle.api.tasks.testing.TestResult

interface Theme {

String beforeSuite(TestDescriptor descriptor)
String suiteText(TestDescriptor descriptor)

String afterTest(TestDescriptor descriptor, TestResult result)
String testText(TestDescriptor descriptor, TestResult result)

String exceptionText(TestDescriptor descriptor, TestResult result)
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package com.adarshr.gradle.testlogger.theme

import com.adarshr.gradle.testlogger.TestLoggerExtension

import static com.adarshr.gradle.testlogger.theme.ThemeType.*

class ThemeFactory {

static Theme loadTheme(ThemeType themeType) {
switch (themeType) {
static Theme getTheme(TestLoggerExtension extension) {
switch (extension.theme) {
case PLAIN:
return new PlainTheme()
return new PlainTheme(extension)
case STANDARD:
return new StandardTheme()
return new StandardTheme(extension)
case MOCHA:
return new MochaTheme()
return new MochaTheme(extension)
default:
throw new IllegalArgumentException("Unsupported theme type ${themeType.name().toLowerCase()}")
throw new IllegalArgumentException("Unsupported theme type ${extension.theme.name().toLowerCase()}")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ abstract class AbstractFunctionalSpec extends Specification {
ansi.render(ansiText)
}

protected BuildResult runMultiple(String args = 'clean test') {
runProject(new File("${TEST_ROOT}/sample-spock-tests"), args)
protected BuildResult run(String project, String args) {
runProject(new File("${TEST_ROOT}/${project}"), args)
}

protected BuildResult runSingle(String buildFragment, String args = 'clean test') {
def projectDir = new File(temporaryFolder.root, 'single-spock-test')
copyDirectoryToDirectory(new File("${TEST_ROOT}/single-spock-test"), temporaryFolder.root)
protected BuildResult run(String project, String buildFragment, String args) {
def projectDir = new File(temporaryFolder.root, project)
copyDirectoryToDirectory(new File("${TEST_ROOT}/${project}"), temporaryFolder.root)
new File(projectDir, 'build.gradle') << buildFragment

runProject(projectDir, args)
Expand Down
Loading