Java Modeling Language

Transcription

Java Modeling Language
Java Modeling Language
Benoit Darties
ESIREM ITR4
benoit.darties@u­bourgogne.fr
Bibliographie

Documents références sur JML :

http://www.eecs.ucf.edu/~leavens/JML/

http://kalysto.org/~nono/teaching/JML/

http://www2.lifl.fr/~nebut/ens/svl/
Java


Langage de programmation orientée Objet

Développé par Sun

Projet OAK (1991),

Java (1995) … Java 1.5 (2004)
Langage interprété

JMV : Java Virtual Machine

Multi-plateforme : Windows, Linux, MacOsX, etc...

Niveau d'abstraction Code / Architecture machine
Java

Compilation :



Produit un fichier Program.class : bytecode
Execution :


javac Program.java
java Fichier
Interprétation du Bytecode par la JVM
Java

concepts de la programmation Objet :

encapsulation de données: public, private, protected

notions d'objets :


classe : « moule » à objet
instance de classes : objets créés avec ce moule

héritage : Class A extends B { … }

polymorphisme
Introduction à JML
Qu'est ce que JML ?

JML : Java Modeling Language

Langage de modélisation formelle

Associé au langage de programmation Java

Inspiré par Eiffel : conception par contrat

Auteur de départ : Gary T. Leavens, 1999

Exprime des propriétés sur les classes Java

Supporté par différents outils :




JML Runtime Assertion Checker
JMLUnit,
ESC/java2
Site de référence : http://jmlspecs.org
Outils JML

Le compilateur jmlc




Compile un fichier java en prenant en compte les
annotations JML qu'il contient pour les transformer
en vérifications à l'exécution (runtimes checks)
Compilateur java amélioré
produit un fichier Bytecode qui pourrait etre
directement interprété par java s'il n'y avait pas de
références vers les packages JML
Le compilateur jmlrac

Runtime Assertion Checker

Ajoute les packages necessaires et appelle java
Invariants, Préconditions,
Postconditions



Invariant : propriété toujours vraie quel que soit
l'état du système
Précondition : propriété vraie avant l'invocation
d'une méthode
Postcondition : propriété vraie après la
terminaison d'une méthode
Conception par contrat

Logique d'Hoare :



Design by Contract : introduit dans langage Eiffel
Contrat entre le système qui invoque une méthode,
et la méthode qui est invoquée :



pré/-postconditions des programmes
L'environnement appelant s'engage à remplir les
préconditions d'une méthode lors de
l'invocation de celle-ci
La méthode s'engage à établir les postconditions
lorsqu'elle est invoquée
La méthode et l'environnement s'engagent
également à maintenir l'invariant de classe
Un premier exemple

Calcul d'une racine carrée : fonction sqrt( )
/**
* @param double x réel positif
* @result double racine carrée de x
*/
Public static double sqrt(double x) {
…
}
Un premier exemple

Calcul d'une racine carrée : fonction sqrt( )
/**
* @param double x réel positif
* @result double racine carrée de x
*/
Définition des /*@
instructions JML :
entre les balises /*@ et *@/
@*/
Public static double sqrt(double x) {
…
}
Un premier exemple

Calcul d'une racine carrée : fonction sqrt( )
/**
* @param double x réel positif
* @result double racine carrée de x
*/
Définition d'une /*@
précondition :
@ requires x >= 0.0;
mot clé 'requires'
@*/
Public static double sqrt(double x) {
…
}
Un premier exemple

Calcul d'une racine carrée : fonction sqrt( )
/**
* @param double x réel positif
* @result double racine carrée de x
*/
Définition d'une /*@
postcondition :
@ requires x >= 0.0;
@ ensures x == \result *\result;
mot clé 'ensures'
@*/
Public static double sqrt(double x) {
…
}
Un premier exemple

requires x >= 0.0;


ensures x == \result * \result;


Précondition assurant que le paramètre x est bien
un réél positif
Postcondition assurant que le résultat \result est
bien la racine carrée de x (à epsilon près)
\result : identifie le résultat d'une méthode
Annotations JML

Une spécification JML s'exprime par un
programme Java annoté :


annotations JML écrites dans le code Java
Placées dans des blocs de commentaires Java
spécifiques :



Une seule ligne commence par //@ …
Un bloc est délimité par /*@ … @*/
Cohérence avec syntaxe Java : un programme
annoté continue de fonctionner normalement
(compilation + exécution)
Clauses de spécification

Modélisation composée de clauses (prédicats)

Décrivent la classe ou les méthodes

Spécification de types : parties statiques du modèle




Spécification de méthodes : parties dynamiques




initially predicatUML
invariant predicatUML
constraint predicatUML

requires predicatUML
diverges predicatUML
assignable predicatUML
ensures predicatUML
signals predicatUML
Spécifications de types

Propriétés portant sur les attributs de la classe



Contrainte initiales : clause initially
Doit être établie à la création de l'objet
Invariant de classe : clause invariant
propriété portant sur les attributs de classe qui
doivent être vrais dans tous les états « visibles » du
système (= état après exécution d'une méthode)
Contrainte historique : clause constraint
propriété entre un état visible et l'état visible
précédent qui doit etre vraie dans tous les états du
système
Spécifications de méthodes

Propriétés relatives aux comportements
autorisés des méthodes




préconditions : clause requires
condition a remplir par le système et les paramètres
pour que la méthode puisse etre appelée
Divergence : clause diverges
condition sous laquelle la méthode ne peut pas se
terminer, i.e. boucles infinies, etc ..
Champs modifiés : clause assignable
liste des attributs modifiés à l'exécution de méthode
Postcondition normale : clause ensures
condition que la méthode s'engage à établir
lorsqu'elle termine normalement
Expression des prédicats JML

Les prédicats JML sont exprimés à l'aide :

des attributs (variables) et paramètres des
méthodes de la classe java annotée

d'appel à des méthodes pures

des opérateurs du langage Java



des opérateurs spécifiques à JML



opérateurs arithmétiques
opérateurs booléens

« nouveaux » opérateurs arithmétiques
« nouveaux » opérateurs booléens
opérateurs avant / après
opérateurs de typage
Objet
Méthodes pures

Méthode pure :

méthode qui ne modifie aucun attribut

peut être utilisée dans les prédicats JML


Les méthodes de consultation des classes de l'API
Java sont considérées comme pures
déclarer une méthode comme étant pure :
class C {
int val;
public /*@ pure */ int getVal() {
return val;
}
}
Opérateurs arithmétiques


Opérateurs binaires
Symbole
Fonction
Champ d'application
+
addition
entiers ou réels
-
soustraction
entiers ou réels
*
multiplication
entiers ou réels
/
division réelle
réels
/
division entière
entiers
%
reste de la division entière
entiers
Opérations généralisées de JML

\sum,
\product, \min,
\max,
\num.of
Opérateurs booléens



opérateurs logiques

opérateurs relationnels
Symbole
Fonction
Symbole
Fonction
&
ET logique
>
supérieur
|
OU logique
>=
supérieur ou égal
^
OU exclusif
<
inférieur
!
négation logique
<=
inférieur ou égal
==>
implication
==
égal
<==>
équivalence
!=
différent
quantification universelle
Symbole
( \forall Type v; predicat1(v); predicat2(v))
Fonction
∀ v, (v ∈Type ∧ predicat1(v) ⇒ predicat2(v) )
quantification existentielle
Symbole
( \exists Type v; predicat1(v); predicat2(v) )
Fonction
∃ v, (v ∈Type ∧ predicat1(v) ∧ predicat2(v) )
Opérateurs avant / après

Certaines clauses font référence à l'état avant
et l'état après l'exécution d'une méthode




\result fait référence au résultat de la méthode
\old(x) permet de faire référence à la valeur de x à
l'état d'avant exécution de la méthode
x fait référence à la valeur de x après exécution de
la méthode
\not.modified(x) est un booléen indiquant si x n'a
pas été modifié lors de l'exécution de la méthode
Opérateurs de typage Objet

Opérateurs de typage Objet




\type(MaClasse) retourne le type décrit par la
spécification de la classe MaClasse
\typeof(monObj) retourne le type de l'objet monObj
< : permet de savoir si un type est un sous-type
d'un autre (héritage)
//@ \typeof(monObj) < : \type(MaClasse) est vrai
si le type de l'objet monObj est un sous-type de la
classe MaClasse. Dit autrement : monObj est une
instance d'une sous-classe
de Maclasse.
Visibilité des spécifications
Portée des spécifications

Les prédicats d'une méthode font partie de son
interface, donc de sa documentation



méthodes privées : ont droit aux prédicats comme
les méthodes publiques
par contre, on n'a pas envie de publier les prédicats
à l'extérieur à de la classe (dans Javadoc par ex)
Spécifications : visibilité comme en Java


public, private, protected, ou limitée au package
par défaut : visibilité de la spécification = visibilité
de la méthode / du type associé au prédicat
Portée des spécifications

Attention :



Ex : impossible de mentionner un attribut Java privé
dans une spécification publique
Mais :

elle décrit comment l'état de l'objet évolue

l'état de l'objet est représenté par ses attributs


une spécification de doit pas autoriser plus d'accès
que le source Java
pour respecter le principe d'encapsulation, les
attributs d'un objet sont le plus souvent privés
les spécifications des attributs
seraient le plus
souvent privées → peu d'utilité
Portée des spécifications

La spécification suivante est incorrecte :

utilisation d'un attribut privé dans une spec publique
public class Disk {
/** size of the disk */
private int size;
//@ requires t > 0
//@ ensures this.size == t;
public Disk(int t) { … }
…
}

La postcondition d'une méthode publique n'a pas
de visibilité sur l'attribut privé
Portée des spécifications

Une solution : spec_public

Autorise un attribut dans toute spécification

Donne une visibilité publique pour les spécifications

revient à dévoiler l'implémentation

fort couplage avec la mise en oeuvre
public class Disk {
/** size of the disk */
private /*@ spec_public @*/ int size;
//@ requires t > 0
//@ ensures this.size == t;
public Disk(int t) { … }
…
}
Portée des spécifications

Autre solution : attribut modèle


ne doit apparaître QUE dans les spécifications

ne doit jamais apparaître dans le code

plus orienté type abstrait de données, plus élégant

Déclarer un attribut abstrait JML qui représente
l'attribut Java dans les spécifications
met en valeur le fait que la spécification représente
une abstraction du comportement
de l'objet
Portée des spécifications

Autre solution : attribut modèle
public class Disk {
/** size of the disk */
//@ public model int size;
private int itsSize;
//@ private represents this.size <­ this.itsSize;
//@ requires t > 0
//@ ensures this.size == t;
public Disk(int t) { … }
…
}
Portée des spécifications

L'attribut modèle size est déclaré :



public pour pouvoir l'utiliser dans une spécification
de n'importe quel niveau de visibilité
avec le modificateur model, qui le distingue d'un
attribut Java classique.
Pour corréler les valeurs de size et itsSize :

clause represents : size a la valeur de itsSize

clause privée, car elle mentionne un attribut privé
Portée des spécifications

Autre exemple :
private int hour;
private int minuts;
private int seconds;
//@ public model long __time;
//@ private represents __time <­ seconds + minuts*60 + hours*60*60;
//@ ensures __time == \old(__time +1) % 24*60*60;
public void tick {
seconds++;
if (seconds == 60) {seconds =0; minuts++;}
if (minuts == 60) {minuts = 0; hours++;}
if (hours == 24) {hours = 0;}
}
Spécification de méthodes et de classes
Spécification de méthodes
et de classes

Quatre cas exclusifs pour la terminaison d'une
méthode, propre à JML :

terminaison normale

terminaison exceptionnelle (levée d'exception)

la JML génère une erreur

la méthode diverge (ne lève pas d'exception, mais
elle ne retourne rien) Spécification de méthodes
et de classes

Précondition:


la précondition doit être vraie lors de l'appel a la
méthode
mot clé requires
//@ requires x >= 0.0; Public static double sqrt(double x) {
... }

valeur par défaut : \not_speficied , interprétée à
true lors de l'exécution et par la majorité des outils
Spécification de méthodes
et de classes

Précondition:


deux clauses requires P1; et requires P2; sont
équivalentes à requires P1 && P2;
l'opérateur && n'est pas commutatif : l'ordre des
préconditions a son importance!
//@ requires o != null;
//@ requires o.getVal() > 10;
différent de //@ requires o.getVal() > 10;
//@ requires o != null;
Spécification de méthodes
et de classes

Précondition :



l'outil jmlc sait générer automatiquement le code
correspondant à la supervision des préconditions
depuis JML 5.3 : pour tout paramètre formel x, x !=
null est une précondition par défaut
pour invalider ce mode par défaut : mot clé nullable
public void nom(/*@ nullable @*/ String x) {
... }
Spécification de méthodes
et de classes

Postcondition :


Si la précondition est vraie lors de l'appel à la
méthode, et que celle-ci se termine normalement,
alors la postcondition normale doit etre vraie
mot clé ensures
//@ requires x >= 0.0;
//@ ensures x == \result *\result;
public static double sqrt(double x) {
... }

valeur par défaut : \not_specified , interprétée à
true lors de l'exécution et par la majorité des outils
Spécification de méthodes
et de classes

Postcondition:


deux clauses ensures P1; et ensures P2; sont
équivalentes à ensures P1 && P2;
l'opérateur && n'est pas commutatif : l'ordre
des postconditions a son importance!

Résultat d'une fonction : \result

Accès aux valeurs avant appel : \old

Attention : \old copie les référence

\old(o) souvent différent de \old(o.a)
Spécification de méthodes
et de classes

Attributs modifiables


Appelés « frame action »
Permet de dire dans une spéc. « ces attributs
peuvent changer ... et rien d'autre ne change »

terme venant du domaine IA

héritage des prouveurs
Spécification de méthodes
et de classes

Attributs modifiables

exemple : classe Point avec coordonnées x et y

l'accesseur en écriture sur x ne doit pas modifier y
//@ ensures this.x == x;
public void setX(int x) {
this.x = x;
}
Spécification de méthodes
et de classes

Attributs modifiables

exemple : classe Point avec coordonnées x et y

l'accesseur en écriture sur x ne doit pas modifier y
//@ ensures this.x == x;
//@ ensures \old(y) == y;
public void setX(int x) {
this.x = x;
y = 1234;
}

ajout d'une post-condition pour détecter l'erreur
Spécification de méthodes
et de classes

Attributs modifiables

exemple : classe Point avec coordonnées x et y

l'accesseur en écriture sur x ne doit pas modifier y
//@ assignable x
//@ ensures this.x == x;
public void setX(int x) {
this.x = x;
}

En JML, on écrira que seul x peut changer
Spécification de méthodes
et de classes

Mot clé assignable






exclut les paramètres formels et les variables
locales
si x est un attribut modèle, impossible d'utiliser
x.toto dans une clause assignable;
valeur par défaut : \not_specified, qui vaut dans la
plupart des outils \everything
autre valeur possible : \nothing;
Raccourci pour assignable \nothing; : déclarer la
méthode pure
La validation des clauses assignable n'est pas
faite à l'exécution (difficile)
Spécification de méthodes
et de classes

Postconditions exceptionnelles





pour indiquer quelles exceptions une méthode peut
lever : mot clé signals_only suivi d'une liste de
noms d'exceptions
valeur par défaut : liste des java.lang.Exception
déclarées dans la clause throws de la méthode
java.lang.Error pas pris en compte
Pour indiquer dans quelles conditions une
exception peut etre levée : mot clé signals suivi du
nom d'exception, suivi d'une condition qui doit etre
vraie si l'exception est levée
par défaut : \not_specified,
interprété par true dans
la plupart des outils
Spécification de méthodes
et de classes

Exemple :
/*@ @*/
public void maFonction(Disk d) throws FullTowerExc eption, IllegalPushException, NullPointerException;
Spécification de méthodes
et de classes

Exemple :
/*@ signals_only IllegalPushException, FullTowerException,NullPointerException;
@*/
public void maFonction(Disk d) throws FullTowerExc eption, IllegalPushException, NullPointerException;
Spécification de méthodes
et de classes

Exemple :
/*@ signals_only IllegalPushException, FullTowerException,NullPointerException;
@ signals (NullPointerException e) d==null;
@ signals (IllegalPushException e) d.size> 10;
@ signals (FullTowerException e) this.isFull();
@*/
public void maFonction(Disk d) throws FullTowerExc eption, IllegalPushException, NullPointerException;
Spécification de méthodes
et de classes

Exemple :
/*@ signals_only IllegalPushException, FullTowerException,NullPointerException;
@ signals (NullPointerException e) d==null;
@ signals (IllegalPushException e) d.size> 10;
@ signals (FullTowerException e) this.isFull();
@*/
public void maFonction(Disk d) throws FullTowerExc eption, IllegalPushException, NullPointerException;

Attention : JML ne lève pas l'exception à la place du
programmeur, il se contente de vérifier que l'exception a été levée à bon escient : verifie que si
FullTowerException a été
levé, isFull() est vrai
Spécification de méthodes
et de classes

Ordre des éléments de spécification

préconditions : requires

clauses assignable

postconditions normales : ensures

postconditions exceptionnelles : signals_only et
signals
Quantificateurs
Quantificateurs


Ajout de quantificateurs par rapport à Eiffel

quantificateur universel \forall

quantificateur existentiel \exists

somme sur une collection de numériques : \sum

produit sur une collection de numériques : \product
Même syntaxe que le for de Java
Quantificateurs

Quantificateurs généralisés

\sum, \product, \min, \max

utilisés avec types numériques, tels int ou float
(\sum int i; 0 <= i && i < 5; i) == 0+1+2+3+4
(\product int i; 0 < i && i < 5; i) == 1*2*3*4
(\max int i; 0 <= i && i < 5; i) == 4
(\min int i; 0 <= i && i < 5; i­1) == ­1
Quantificateurs

Exemple sur listes : type List

Typer une liste en JML
List l = ... ;
/*@ invariant (\forall Object o; l.contains(o); o instanceOf String); @*/

Poser une contrainte d'initialisation
List l = ... ;
/*@ invariant (\exists Object o; l.contains(o); o != null); @*/
Quantificateurs

Exemple sur listes : type List

Spécifier un résultat
List l = ... ;
/*@ \result = \sum (Integer i; l.contains(i); i.intValue()); @*/

Contraintes sur les éléments d'un tableau
String[] array = ... ;
/*@ (\forall int i; 0 <= i && i < array.length; array[i] != null); @*/
Spécification par cas
Spécification par cas

Permet de développer des spécifications en
mini-contrats

Mot clé : also

Permet d'écrire des spécifications de la forme:

Dans le cas précond1, alors postcond1;
et aussi : dans le cas précond2, alors postcond2;

etc ...
Spécification par cas

Exemple : calcul d'une valeur absolue
//@ ensures x >=0 ==> \result == x;
//@ ensures x <0 ==> \result == ­x;
public /*@ pure @*/ int valAbs(int x) { ... }
/*@ requires x >= 0;
@ ensures \result == x;
@ also
@ requires x < 0;
@ ensures \result == ­x;
@*/
public /*@ pure @*/ int valAbs(int x) {...} Spécification par cas

Exemple : calcul d'une valeur absolue
/*@ requires x >= 0 || x < 0;
@ ensures \old(x>=0) ==> \result == x;
@ ensures \old(x<0) ==> \result == ­x;
@*/
public /*@ pure @*/ int valAbs(int x) { ... } Application
Gestionnaire de cours

Mise en place d'un gestionnaire de cours :

Un cours a un nombre max de places disponibles

Un étudiant (nom prénom) peut s'inscrire à un cours

Seul un étudiant encore jamais inscrit peut s'inscrire

Un étudiant inscrit peut passer l'examen



S'il réussi l'examen, il obtient le diplome. Sinon il
est collé
Un étudiant collé peut repasser une fois l'examen
avant d'etre définitivement refusé.
etc ...
Gestionnaire de cours


Une classe Etudiant

deux attributs : nom et prénom

1 constructeur : Etudiant (nom, prénom)

1 méthode : toString()
Une classe Cours

5 attributs : max, inscrits, collé, refusé, diplômé

1 constructeur : Cours(maxi)

4 méthodes :
nouvel_etudiant(etudiant), test_reussi(etudiant),
test_rate_colle(etudiant),
test_rate_refuse(etudiant)
Gestionnaire de cours

classe Etudiant
public class Etudiant {
private String nom ;
private String prenom ;
Etudiant(String nom, String prenom) {
this.nom = nom ;
this.prenom = prenom ;
}
public String toString() {
return prenom + " " + nom ;
}
}
Gestionnaire de cours

classe Etudiant
public class Etudiant {
private /*@ spec public non null */ String nom ;
private /*@ spec public non null */ String prenom ;
Etudiant(String nom, String prenom) {
this.nom = nom ;
this.prenom = prenom ;
}
public String toString() {
return prenom + " " + nom ;
}
}
Gestionnaire de cours

classe Etudiant
public class Etudiant {
private /*@ spec public non null */ String nom ;
private /*@ spec public non null */ String prenom ;
//@ invariant !nom.equals("") & !prenom.equals("") ;
Etudiant(String nom, String prenom) {
this.nom = nom ;
this.prenom = prenom ;
}
public String toString() {
return prenom + " " + nom ;
}
}
Gestionnaire de cours

classe Cours
public class Cours {
private int max ;
private HashSet inscrits ;
private HashSet colles ;
private HashSet refuses ;
private HashSet diplomes ;
Cours(int maxi) {
max = maxi ;
inscrits = new HashSet(max) ;
colles = new HashSet(max) ;
refuses = new HashSet(max) ;
diplomes = new HashSet(max) ;
}
Gestionnaire de cours

classe Cours
public void nouvel_etudiant(Etudiant etudiant) {
inscrits.add(etudiant) ;
}
public void_test_reussi(Etudiant etudiant) {
inscrits.remove(etudiant) ;
diplomes.add(etudiant) ;
}
public void test_rate_colle(Etudiant etudiant) {
colles.add(etudiant) ;
}
}
Gestionnaire de cours

classe Cours
public class Cours {
private /*@ spec public *@/ int max ;
private /*@ spec public *@/ HashSet inscrits ;
private /*@ spec public *@/ HashSet colles ;
private /*@ spec public *@/ HashSet refuses ;
private /*@ spec public *@/ HashSet diplomes ;
Gestionnaire de cours

classe Cours
public class Cours {
private /*@ spec public *@/ int max ;
private /*@ spec public *@/ HashSet inscrits ;
private /*@ spec public *@/ HashSet colles ;
private /*@ spec public *@/ HashSet refuses ;
private /*@ spec public *@/ HashSet diplomes ;
/*@
@ invariant max > 0 ;
@ invariant inscrits.size() <= max ;
@ invariant (\forall Etudiant e ; colles.contains(e) ; inscrits.contains(e)) ;
@*/
Gestionnaire de cours

classe Cours
/*@
@ initially inscrits.isEmpty() ;
@ initially colles.isEmpty() ;
@ initially refuses.isEmpty() ;
@ initially diplomes.isEmpty() ;
@*/
Gestionnaire de cours

classe Cours
/*@
@ initially inscrits.isEmpty() ;
@ initially colles.isEmpty() ;
@ initially refuses.isEmpty() ;
@ initially diplomes.isEmpty() ;
@*/
Cours(int maxi) {
max = maxi ;
inscrits = new HashSet(max) ;
colles = new HashSet(max) ;
refuses = new HashSet(max) ;
diplomes = new HashSet(max) ;
}
Gestionnaire de cours

classe Cours
/*@
@ initially inscrits.isEmpty() ;
@ initially colles.isEmpty() ;
@ initially refuses.isEmpty() ;
@ initially diplomes.isEmpty() ;
@*/
//@ requires maxi >0;
Cours(int maxi) {
max = maxi ;
inscrits = new HashSet(max) ;
colles = new HashSet(max) ;
refuses = new HashSet(max) ;
diplomes = new HashSet(max) ;
}
Gestionnaire de cours

classe Cours
public void nouvel_etudiant(Etudiant etudiant){
inscrits.add(etudiant) ;
}
Gestionnaire de cours

classe Cours
/*@
@ requires !inscrits.contains(etudiant) ;
@ requires !diplomes.contains(etudiant) ;
@ requires !refuses.contains(etudiant) ;
@ requires inscrits.size() < max ;
@ ensures inscrits.contains(etudiant) ;
@*/
public void nouvel_etudiant(Etudiant etudiant){
inscrits.add(etudiant) ;
}
Gestionnaire de cours

classe Cours
public void test_reussi(Etudiant etudiant) {
inscrits.remove(etudiant) ;
diplomes.add(etudiant) ;
}
Gestionnaire de cours

classe Cours
/*@
@ requires inscrits.contains(etudiant) ;
@ ensures !inscrits.contains(etudiant) ;
@ ensures diplomes.contains(etudiant) ;
@*/
public void test_reussi(Etudiant etudiant) {
inscrits.remove(etudiant) ;
diplomes.add(etudiant) ;
}
Gestionnaire de cours

classe Cours
public void test_rate_colle(Etudiant etudiant) {
colles.add(etudiant) ;
}
Gestionnaire de cours

classe Cours
/*@
@ requires inscrits.contains(etudiant) ;
@ requires !colles.contains(etudiant) ;
@ ensures colles.contains(etudiant) ;
@*/
public void test_rate_colle(Etudiant etudiant) {
colles.add(etudiant) ;
}
Gestionnaire de cours

classe Cours
public void test rate refuse(Etudiant etudiant){
inscrits.remove(etudiant) ;
colles.remove(etudiant) ;
refuses.add(etudiant) ;
}
Gestionnaire de cours

classe Cours
/*@
@ requires inscrits.contains(etudiant) ;
@ requires colles.contains(etudiant) ;
@ ensures !inscrits.contains(etudiant) ;
@ ensures !colles.contains(etudiant) ;
@ ensures refuses.contains(etudiant) ;
@*/
public void test rate refuse(Etudiant etudiant){
inscrits.remove(etudiant) ;
colles.remove(etudiant) ;
refuses.add(etudiant) ;
}