Happy !

AlainRastoul / IceCompiler

Project infos

License MIT
Tags design by contracts, asserts, metalink
Creation date 2016-02-25
Website

Monticello registration

About IceCompiler

Overview

A POC implementation of a design by contract facility for Pharo.

IceCompiler is a small front-end to the compiler that recompile classes (annotate AST of compiled methods) with Design By Contract contract methods embedded in the source of the class.

The motivation for such a tool is that it should help bullet proofing a software done with Pharo, as it is sometimes difficult to see what is going on underneath (especially what is wrong).

Usage

IceCompiler usage is a 4 steps process:

  • Implement methods that will check contracts (contract methods) in the same class than the one you want tot test, in a {Ice-contracts} protocol to organize code (for example).

  • Compile the class with contracts (IceCompile the class)

  • Run your code and check for reported errors.

  • Clean the compiled code when done, IceCompiled methods are much slower than normal methods

Contracts implementation

Contracts are implemented as instance methods of the object with pragma notations (see below). Contract methods must return true or false. They are not checked on entry or exit of contructors and other contracts. They can be Invariants, Precondition or Postcondition

Invariants

Invariants are checks done on entry and exit of every method who is not a contract or constructor. Class invariant contract methods are annoted with a

<contract: #invariant> .

Pre conditions

Preconditions are checks done on entry of a method. They ensure that a required condition is met on entry.

Pre condition contracts are annoted with a pre annotation pragma:

<contract: #pre on: #aMethod: >

or with

<contract: #pre on: #( #aMethod1 #aMethod2... aMethodn) >

to apply the contract to several methods (does not work yet)

Post conditions

Post conditions are contract that must be ensured by the method. They are checked on exit of the method.

Post condition contracts are annoted with an post annotation:

<contract: #post on: #add: >

or with

<contract: #post on: #( #aMethod1 #aMethod2... aMethodn) >

to apply the contract to several methods (does not work yet)

Important:

  • Do not throw errors from the contract method with error:, signals or whatever, it would break the workflow of the object and when testing sensible classes could break the image.
  • the error reporting is done by returning true of false on the contract method
  • a contract method who doesn't return true or false will be reported as a Malformed contract error

Examples

In these examples FakeRTGroup is a subclass of FakeOrderedCollection

A Post condition for FakeOrderedCollection class

``` postAdd: anObject

<contract: #post on: #add: >

"on exit of add: anObject, the collection (self) must include the object"
^  self includes: anObject .

```

this post condition will be added to FakeOrderedCollection>>add: method and all subclasses implementing add:

An invariant on FakeOrderedCollection and subclasses

``` firstIndexInvariant

<contract: #invariant>

^  firstIndex > 0

```

This check will be done on every entry and exit of every method of FakeOrderedCollection and FakeRTGroup.

See FakeOrderedCollection , RTGroup and tests for other examples (in progress).

Compiling with contracts

To compile the class:

```

IceCompiler compile: MyClass .

```

the class with all its subclasses will be compiled with contract checks embedded.

Looking for reported errors

Run your code. Open the IceReporter (an inspector) to see reported errors

IceReporter openIfNotEmpty .

see IceReporter class side for other facilities (logging to file and/or memory, stacks traces ).

IceReporter is just a blackbox recorder, it does not use Transcript or other evolved facilities in order to be as light as possible with less side effects.

It records limited stack traces as strings to avoid hanging references on objects, although it would be more interesting to store context (much more information with inspector) .

Cleaning the code

After some test runs, recompile the classes with the standard compiler or with

IceCompiler clean: MyClass

Notes

Asserts, breakpoints or contracts

Asserts and breakpoints are fine.

They are unvaluable tools for debugging , but sometimes they are difficult to use with system classes or window events and could even break the system. They may also change the workflow of the running system or induce other side effects that makes debugging difficult.

Contracts do not superseed breakpoints or asserts, they offer a different way of checking a system, with a declarative way that break apart checking the system from it's original implementation.

The current implementation does not enforce contracts, it does not halt the system, it does no assertions, no halts, it only reports contract violations in a blackbox for future explorations. This recording-only approach let the system live unaffected by contract checking.

final notes

  • The IceCompiler has not been totally IceCompiled with contracts yet (in progress)

  • It currently does not support checking the returned value of methods.

  • There is a small mocking class under IceCompiler-Core-Mocking that may be very useful for other tests purposes