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
