-
Notifications
You must be signed in to change notification settings - Fork 11
Home
This project aims to provide contract annotations that support specification of class-invariants, pre- and postconditions on methods and loop invariants towards better software quality in Groovy/Grails projects.
GContracts supports the following features found in Design by Contract™:
- definition of class invariants, preconditions and postconditions
- inheritance of class invariants, pre- and postconditions
- usage of old and result variable in the postconditions assertion
- assertion injection in Groovy generated setter methods
- usage of Groovy Power asserts for better assert error messages
Up to now the project provides 3 annotations: @Invariant
, @Require
and @Ensures
– all of them work with so-called closure annotations, allowing to specify arbitrary code pieces as annotation parameters:
@Grab(group='org.gcontracts', module='gcontracts', version='[1.1.1,)') import org.gcontracts.annotations.*
@Invariant({ elements != null }) class Stack {
private List elements
@Ensures({ is_empty() }) public Stack() { elements = [] }
@Requires({ preElements?.size() > 0 }) @Ensures({ !is_empty() }) public Stack(List preElements) { elements = preElements }
def boolean is_empty() { elements.isEmpty() }
@Requires({ !is_empty() }) def last_item() { elements.last() }
def count() { elements.size() }
@Ensures({ result == true ? count() > 0 : count() >= 0 }) def boolean has(def item) { elements.contains(item) }
@Ensures({ last_item() == item }) def put(def item) { elements.push(item) }
@Requires({ !is_empty() }) @Ensures({ last_item() == item }) def replace(def item) { remove() elements.push(item) }
@Requires({ !is_empty() }) @Ensures({ result != null }) def remove() { elements.pop() }
def String toString() { elements.toString() } }
The example above specifies a class-invariant and methods with pre- and post-conditions. Note, that preconditions may reference method arguments and post-conditions have access to the method’s result with the result
variable and old instance variables values with old
.
Indeed, Groovy AST transformations change these assertion annotations into Java assertion statements (can be turned on and off with a JVM param) and inject them at appropriate places, e.g. class-invariants are used to check an object’s state before and after each method call.
In order to use GContracts in a Maven project, following this wiki’s guide (Wiki page: Maven).
Otherwise, download the GContracts binary from github’s download section and throw it in the application class path. groovyc automatically detects the jar and injects GContracts assertions.
The project is currently in alpha phase and not ment to be used in production environments, but feel free if you want to contribute and improve things.