Skip to content
This repository has been archived by the owner on Jan 7, 2020. It is now read-only.
andresteingress edited this page Oct 22, 2010 · 44 revisions

Welcome to GContracts – Programming by Contract with Groovy!


Flattr this

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

An Example

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.

How to add GContracts to a project

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.

Notice

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.