$30
In this exercise, you will use two static analysis tools to test a program: a
bug finder named SpotBugs and a linter named CheckStyle, SpotBugs and
CheckStyle work in similar ways in that both look for patterns that are either
symptomatic of a bug (former) or are bad coding style (latter). So we will
look at them together first. Later in Part 2, we will do model checking using
the Java Path Finder (JPF) which is much more rigorous in proving a program
correct.
## DrunkCarnivalShooter
DrunkCarnivalShooter is a simple text-based game where the player goes to a
carnival shooting range and tries to win the prize by shooting all 4 provied
targets. The player can designate what target to shoot for pressing 0-3. But
since the player is drunk, there is an equal chance of the player shooting left
or right as shooting straight. Refer to the file
[sample_run.txt](sample_run.txt) for an example game play session. You can
also try playing it yourself using the reference implementation:
```
$ java -jar DrunkCarnivalShooter.jar
```
To run the DrunkCarnivalShooter using the current implementation (for Windows users):
```
$ run.bat
```
For Mac or Linux:
```
$ bash run.sh
```
Now the current implementation contains several bugs. In fact, the game throws
an exception immediately at start up:
```
$ java -cp bin;jpf-core/build/* DrunkCarnivalShooterImpl
Exception in thread "main" java.lang.NullPointerException
at DrunkCarnivalShooterImpl.<init(DrunkCarnivalShooterImpl.java:31)
at DrunkCarnivalShooterImpl.main(DrunkCarnivalShooterImpl.java:150)
```
In this exercise, we are going to try to debug the program using static
analysis instead of dynamic testing. So now let's go and try to find some
defects!
## Applying SpotBugs and CheckStyle
Try running both tools on DrunkCarnivalShooterImpl.java. As usual, I've
provided scripts to run each tool.
To run CheckStyle (Windows users):
```
$ runCheckstyle.bat
```
To run CheckStyle (Mac/Linux users):
```
$ bash runCheckstyle.sh
```
To run SpotBugs (Windows users):
```
$ runSpotbugs.bat
```
To run SpotBugs (Mac/Linux users):
```
$ bash runSpotbugs.sh
```
CheckStyle and Spotbugs should print out several warnings each. Refer to the
below references to find out what each warning means at fix your code at the
corresponding source code line:
* CheckStyle reference: https://checkstyle.sourceforge.io/checks.html
If you don't understand a CheckStyle warning, read the corresponding entry inside google\_checks\_modified.xml under the checkstyle-jars folder and the above reference.
* SpotBugs reference: https://spotbugs.readthedocs.io/en/latest/bugDescriptions.html
* There is a GUI for SpotBugs if that is what you prefer. You can launch the GUI by using the following command:
```
$ java -jar spotbugs-4.0.0-beta4/lib/spotbugs.jar
```
The following link contains a short tutorial on how to use the GUI:
https://spotbugs.readthedocs.io/en/latest/gui.html
SpotBugs will complain about among other things a warning type called
"ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD". Look up the meaning of this error
type in the above SpotBugs reference. It is saying that you should not update
a static variable from an instance method. I have seen many of you do this a
lot in your assignments. You would declare variables that should really be
instance variables to be static. I don't know where you picked up that
programming habit, but that goes against all OOP principles. If you are still
unsure about when to use static and when to use instance variables, here is a
good tutorial:
https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
After removing all warnings, you should see the following ouput for each.
Checkstyle output:
```
$ java -jar checkstyle-jars /checkstyle-7.0-all.jar -c checkstyle-jars/google_checks_modified.xml src/DrunkCarnivalShooterImpl.java
Starting audit...
Audit done.
```
SpotBugs output:
```
$ java -jar spotbugs-4.0.0-beta4/lib/spotbugs.jar -textui -low -effort:max -longBugCodes -exclude spotbugs-4.0.0-beta4/my_exclude_filter.xml bin/*.class
The following classes needed for analysis were missing:
org.junit.runner.JUnitCore
org.junit.runner.Result
org.junit.runner.notification.Failure
```
The missing classes are JUnit library classes. We are not interested in
debugging the JUnit library, so we did not pass it to SpotBugs.
After fixing all the warning, now the program should at least start up properly, when run with run.bat:
```
$ java -cp bin;jpf-core/build/* DrunkCarnivalShooterImpl
Round #0: || || || ||
Choose your target (0-3):
```
Yay! But we are note done yet. There are still bugs remaining. Try repeatedly shooting the first target by choosing 0.
```
$ java -cp bin;jpf-core/build/* DrunkCarnivalShooterImpl
Round #0: || || || ||
Choose your target (0-3):
0
...
Round #3: || || ||
Choose your target (0-3):
0
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(ArrayList.java:422)
at java.util.ArrayList.get(ArrayList.java:435)
at DrunkCarnivalShooterImpl.isTargetStanding(DrunkCarnivalShooterImpl.java:125)
at DrunkCarnivalShooterImpl.takeDownTarget(DrunkCarnivalShooterImpl.java:108)
at DrunkCarnivalShooterImpl.shoot(DrunkCarnivalShooterImpl.java:89)
at DrunkCarnivalShooterImpl.main(DrunkCarnivalShooterImpl.java:158)
```
The bug does not manifest in a deterministic way due to the randomness but you
will trigger it soon enough. Or you may encounter another bug where the game
ends prematurely even when there are targets remaining. These bugs are bugs in
the logic of the program and SpotBugs is not very good at finding these types
of bugs. It only finds bugs that match a certain pattern.
### Lessons on Pattern Matching
Both linters (CheckStyle) and bug finders (SpotBugs) work by pattern matching.
Pattern matching can be good at finding simple bugs that are recurrent across
projects and can even catch errors in your documentation. What they are not
good for is finding problems in your program logic (as seen above). For that,
you need dynamic testing that actually executes the program to check program
behavior. Or, you can use model checking that is able to *prove* that certain
correctness properties hold for all situations, even for random programs like
this one