Make Android Gradle display unit test failure messages

By default, Gradle does not show you what happened when a unit test failed:

$ ./gradlew test
...
MyTest > Black_is_white FAILED
    org.junit.ComparisonFailure at MyTest.java:6
    ^^^ WHAT ACTUALLY FAILED????
...

This is insane, and can be fixed (thanks to mrhaki) by editing build.gradle to add:

// NOTE: this is the non-Android solution - add to build.gradle
test {
    testLogging {
        exceptionFormat = 'full'
    }
}

The above doesn’t work with Android, but something similar does:

// Android solution: add this to app/build.gradle
android.testOptions.unitTests.all {
    testLogging {
        exceptionFormat = "full"
    }
}

And sanity prevails:

$ ./gradlew test
...
MyTest > Black_is_white FAILED
    org.junit.ComparisonFailure:
    expected:<[black]> but was:<[white]>
        at org.junit.Assert.assertEquals(Assert.java:115)
        at org.junit.Assert.assertEquals(Assert.java:144)
        at MyTest.Black_is_white(MyTest.java:6)
...

Files for plain Gradle:

$ cat build.gradle
apply plugin: 'java'

repositories {
    mavenCentral()
}
     
dependencies {
    testCompile 'junit:junit:[4,)'
}

test {
    testLogging {
        exceptionFormat = 'full'
    }
}

$ cat src/test/java/MyTest.java
public class MyTest
{
    @org.junit.Test
    public void Black_is_white()
    {
        org.junit.Assert.assertEquals("black", "white");
    }
}

Files for Android+Gradle

$ cat build.gradle
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.1'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

$ cat app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.artificialworlds.testapp">
</manifest>

$ cat app/src/test/java/MyTest.java
public class MyTest
{
    @org.junit.Test
    public void Black_is_white()
    {
        org.junit.Assert.assertEquals("black", "white");
    }
}

$ cat build.gradle
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.1'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

$ cat local.properties
sdk.dir=/home/andy/Android/Sdk

$ cat settings.gradle
include ':app'

Iterating over the lines of a file in Java

If you’re trying to write a standard command-line tool in Java you are going to experience pain.

In Python, if we want to do something with each line on input to your program, we can do something like:

import sys
for ln in sys.stdin:
    print(ln)  # (We have an extra newline but who's counting?)

In Java, after some fighting, the two closest alternatives I can find are:

import java.util.Scanner;
class IterateInputScanner {
    public static void main(String[] args) {
        for(String ln : (Iterable)(() -> new Scanner(System.in).useDelimiter("\n"))) {
            System.out.println(ln);
        }
    }
}

or, less fashionably, and even more horribly:

import java.io.BufferedReader;
import java.io.InputStreamReader;
class IterateInputReader {
    public static void main(String[] args) throws java.io.IOException {
        BufferedReader reader =
            new BufferedReader(new InputStreamReader(System.in));
        String ln;
        while((ln = reader.readLine()) != null) {
            System.out.println(ln);
        }
    }
}

Note that if you are reading from a stream other than stdin you will probably want to wrap this in a try-with-resources to close the stream when you’ve finished.

Take your pick, and I hope it saves you some fighting.

Setting up a sane Maven project

Today I have spent hours trying to get wrangle Maven into letting me set up a sane Java project. The hardest parts were enforcing warnings-as-errors, and getting Maven to shut up a bit.

Some code that warns

My first problem was writing some Java code that causes the compiler to emit warnings. For some reason I can’t understand, my Java 1.8 compiler was not emitting warnings (even with -Xlint:all) for unused variables, use of deprecated methods, or unknown @SuppressWarnings types (suggestions from SO 1752607).

Instead, I had to use an unnecessary cast:

$ cat src/tast/java/ExampleTest.java
public class ExampleTest {
    public void warn() {
        String fixmePlease = (String)"Hello";
    }
}

Now, finally, I got a warning:

$ javac -Xlint:all src/test/ExampleTest.java
src/test/ExampleTest.java:3: warning: [cast] redundant cast to String
        String s = (String) "Hello!";
                   ^
1 warning

Maven compiler settings for warnings-as-errors

I tried a vast set of combinations of properties like maven.compiler.failOnWarning and maven.compiler.fork (as specified in the maven compiler plugin docs) before giving up on properties. Making a property called maven.compiler.failOnWarning seems to have no effect whatsoever, ever.

So I decided I must try the (very verbose) plugin tag containing a configuration tag, as also specified in the maven compiler plugin docs. After a lot of messing about with flags that seemed incompatible, and Maven silently ignoring things it didn’t understand, I came to a working config.

On the way, I discovered that setting the “fork” property to true is a non-starter, because Maven simply drops the compiler output in that case, meaning you can’t see what is going wrong when it does.

Finally, I had a pom file like this:

cat pom.xml
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>Example</artifactId>
    <packaging>jar</packaging>
    <version>0.0.1</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <failOnWarning>true</failOnWarning>
                    <showWarnings>true</showWarnings>
                    <compilerArgs>
                        <arg>-Xlint:all</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
        </plugins>
    </build>
     <dependencies>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.12</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
</project>

Which manages successfully to tell the compiler to show all warnings, and to fail when it sees one. (Thanks to SO 9192613, among others.)

I dare not change anything, for fear that it will stop working again without any explanation.

Quieting Maven

If you tell Maven to be quiet with -q or -e it will merrily fail the build because of a warning, but not tell you what the warning was.

Maven does not appear to have a command line option to set the log level to display warnings and errors only, but you can force it to do so by setting the environment variable MAVEN_OPTS like this:

MAVEN_OPTS=MAVEN_OPTS=-Dorg.slf4j.simpleLogger.defaultLogLevel=warn mvn clean test-compile

(Thanks to SO 4782089.)

And, with some guesswork (partly based on Configuring Maven) I found that if I put something similar in .mvn/jvm.config I didn’t have to type it every time:

$ cat .mvn/jvm.config 
-Dorg.slf4j.simpleLogger.defaultLogLevel=warn

Failing on warnings, and seeing them!

I don’t know whether to feel triumphant or defeated, but, it works!

$ mvn clean test-compile 
[WARNING] COMPILATION WARNING : 
[WARNING] src/test/java/ExampleTest.java:[3,20] redundant cast to java.lang.String
[ERROR] COMPILATION ERROR : 
[ERROR] src/test/java/ExampleTest.java: warnings found and -Werror specified
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.6.0:testCompile (default-testCompile) on project unmatcheddrrepair: Compilation failure
[ERROR] src/test/java/ExampleTest.java: warnings found and -Werror specified
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

I wish I could suppress double-reporting of the error, and the extra rubbish at the end (and the super-long absolute paths of each file that push the actual errors off the side of the screen), but at this point, I must try and do what I was trying to do in the first place.

Guess how much I am liking Maven at this point.

Simple example of Netty 4 usage

I feel the title of this post over-promises, since I was not able to make an example that seemed simple to me.

Anyway, here is a near-minimal example of how to use Netty to make a server that shouts back at you whatever you say:

NettyExample.java:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import java.nio.charset.Charset;

class NettyExample
{
    public static void main( String[] args ) throws Exception
    {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try
        {
            new ServerBootstrap()
                .group( bossGroup, workerGroup )
                .channel( NioServerSocketChannel.class )
                .childHandler( new Init() )
                .bind( 1337 ).sync().channel().closeFuture().sync();
        }
        finally
        {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private static class Init extends ChannelInitializer
    {
        @Override
        public void
        initChannel( SocketChannel ch ) throws Exception
        {
            ch.pipeline().addLast( new ShoutyHandler() );
        }
    }

    private static class ShoutyHandler extends ChannelInboundHandlerAdapter
    {
        @Override
        public void channelRead( ChannelHandlerContext ctx, Object msg )
        {
            try
            {
                Charset utf8 = CharsetUtil.UTF_8;
                String in = ( (ByteBuf)msg ).toString( utf8 );
                String out = in.toUpperCase(); // Shout!
                ctx.writeAndFlush( Unpooled.copiedBuffer( out, utf8 ) );
            }
            finally
            {
                ReferenceCountUtil.release( msg );
            }
        }

        @Override
        public void exceptionCaught(
            ChannelHandlerContext ctx, Throwable cause )
        {
            cause.printStackTrace();
            ctx.close();
        }
    }
}

The lines that actually do something useful are highlighted in red. If anyone knows how to make it shorter, please comment below. It seems a lot to me.

To run this, do:

sudo apt-get install openjdk-8-jdk
wget 'http://search.maven.org/remotecontent?filepath=io/netty/netty-all/4.1.5.Final/netty-all-4.1.5.Final.jar -O netty-all-4.1.5.Final.jar'
javac -Werror -cp netty-all-4.1.5.Final.jar:. NettyExample.java && java -cp netty-all-4.1.5.Final.jar:. NettyExample

Then in another terminal:

echo "Hello, world" | nc localhost 1337

and observe the response:

HELLO, WORLD

Comparison with Node.js

Just for comparison, here is an approximate equivalent in Node.js:

shouty.js:

var net = require('net');

var server = net.createServer(
    function( socket ) {
        socket.setEncoding('utf8');
        socket.on(
            'data',
            function( data ) {
                socket.end( data.toUpperCase() );
            }
        )
    }
);

server.listen( 1337, "localhost" );

To run it, do:

sudo apt-get install nodejs-legacy
node shouty.js

Then in another terminal:

echo "Hello, world" | nc localhost 1337

and observe the response:

HELLO, WORLD

Ambiguous names in Java due to non-normalised unicode – but all OK in Python

In Java and several other languages, identifiers (e.g. method names) are allowed to contain unicode characters.

Unfortunately, some combinations of unicode characters are logically identical. For example, á (one character: Latin Small Letter a with Acute U+00E1) is the same as á (two characters: Latin Small Letter A U+0061, and Non-spacing Acute Accent U+0301). These combinations are not just similar – they are identical by definition.

Java does not do any normalisation on your code before compiling it, so two identifiers containing equivalent but different unicode combinations are considered different (ref: JLS 7 section 3.8).

$ cat U.java 
public class U {
    static String \u00e1() { return "A WITH ACUTE"; }
    static String a\u0301() { return "A + NON-SPACING ACUTE"; }
    public static void main(String[] a) {
        System.out.println(á());
        System.out.println(á());
    }
}
$ javac U.java && java U
A WITH ACUTE
A + NON-SPACING ACUTE

We can define and use two functions called á and á and they are totally independent entities.

But don’t do this.

Python 3 also allows unicode characters in identifiers, but it avoids the above problem by normalising them (ref: Python 3 Reference, section 2.3):

$ cat U.py 
#!/usr/bin/env python3

def á():
    print("A WITH ACUTE")

def á():
    print("A + NON-SPACING ACUTE")

á()
á()

$ hexdump -C U.py 
23 21 2f 75 73 72 2f 62  69 6e 2f 65 6e 76 20 70  |#!/usr/bin/env p|
79 74 68 6f 6e 33 0a 0a  64 65 66 20 c3 a1 28 29  |ython3..def ..()|
3a 0a 20 20 20 20 70 72  69 6e 74 28 22 41 20 57  |:.    print("A W|
49 54 48 20 41 43 55 54  45 22 29 0a 0a 64 65 66  |ITH ACUTE")..def|
20 61 cc 81 28 29 3a 0a  20 20 20 20 70 72 69 6e  | a..():.    prin|
74 28 22 41 20 2b 20 4e  4f 4e 2d 53 50 41 43 49  |t("A + NON-SPACI|
4e 47 20 41 43 55 54 45  22 29 0a 0a c3 a1 28 29  |NG ACUTE")....()|
0a 61 cc 81 28 29 0a 0a                           |.a..()..|
$ ./U.py 
A + NON-SPACING ACUTE
A + NON-SPACING ACUTE

(Legend: A WITH ACUTE, A + NON-SPACING ACUTE)

The second definition overwrites the first because they are considered identical. You can call it via either way of saying its name.

Both ways of working are scary, but I’d definitely choose the Python 3 way if I had to.