Skip to content
Snippets Groups Projects
Commit 0fadff48 authored by PIERRON Laurent's avatar PIERRON Laurent :man_in_tuxedo_tone1:
Browse files

initial commit

parents
Branches
No related tags found
No related merge requests found
Pipeline #10442 passed
target
.DS_Store
.vscode
# This file is a template, and might need editing before it works on your project.
# This is a sample GitLab CI/CD configuration file that should run without any modifications.
# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
# it uses echo commands to simulate the pipeline execution.
#
# A pipeline is composed of independent jobs that run scripts, grouped into stages.
# Stages run in sequential order, but jobs within stages run in parallel.
#
# For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages
#
# You can copy and paste this template into a new `.gitlab-ci.yml` file.
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
#
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
image: maven:3.8-openjdk-18-slim
stages: # List of stages for jobs, and their order of execution
- build
- test
- deploy
build-job: # This job runs in the build stage, which runs first.
stage: build
script:
- echo "Compiling the code..."
- mvn install -B
- echo "Compile complete."
unit-test-job: # This job runs in the test stage.
stage: test # It only starts when the job in the build stage completes successfully.
script:
- echo "Running unit tests... This will take about 60 seconds."
- sleep 60
- echo "Code coverage is 90%"
lint-test-job: # This job also runs in the test stage.
stage: test # It can run at the same time as unit-test-job (in parallel).
script:
- echo "Linting code... This will take about 10 seconds."
- sleep 10
- echo "No lint issues found."
deploy-job: # This job runs in the deploy stage.
stage: deploy # It only runs when *both* jobs in the test stage complete successfully.
environment: production
script:
- echo "Deploying application..."
- echo "Application successfully deployed."
------------------------------------------------------------------------
Super Calculator
Author: Hacker T. Largebrain
------------------------------------------------------------------------
This program implements a highly efficient calculating engine for
a pocket calculator. It includes a complete test rig to demonstrate
that the engine works as it should.
README.md 0 → 100755
# Projet: calculator
Auteurs: Michael Kölling and David J. Barnes
Traduction: Laurent Pierron
Ce projet fait partie du matériel pour le livre
**Objects First with Java - A Practical Introduction using BlueJ
Fifth edition
David J. Barnes and Michael Kölling
Pearson Education, 2012**
Il est expliqué dans le chapitre 7.
Une réalisation d'une calculatrice de bureau. Cet exemple renforce les concepts vus précédemment et est utilisé pour discuter le débogage et le test.
Une version avec une interface graphique est incluse dans la branche `calculator-gui`.
- - -
## Préparation du projet
1. Créer un clone du projet **calculator** sur votre machine.
2. Créez une branche avec votre nom de login.
3. Synchronisez votre branche sur https://gitlab.univ-lorraine.fr.
- - -
## Expression du besoin
On vous a demandé de joindre une équipe chargée de développer une calculatrice logicielle, car un des membres essentiels de l'équipe, Hacker T. Largebrain, a été promu pour diriger un autre projet.
Avant de quitter le projet, Hacker a assuré à l'équipe que vous rejoignez que la réalisation de la partie de calculatrice dont il était responsable était terminée et complètement **testée**. Il a même écrit un logiciel de test pour vérifier que c'était le cas. On vous a demandé de reprendre la classe `CalcEngine` et de vous assurer simplement qu'elle est correctement documentée avant son intégration aux classes développées par les coéquipiers.
![calculatrice.png](images/2090535594-calculatrice.png "image d'une calculatrice")
Dans l'application des bonnes pratiques de découpage des applications, le projet de calculatrice a été conçu en séparant l'interface utilisateur du moteur de calcul. La première version, que nous étudierons ici, fonctionnera avec une interface graphique (*GUI*) montrée ci-dessous. Plus tard la même calculatrice pourra être utilisée pour créer une application Web et une application pour smartphone. En préparation de cela l'application a été divisée en deux classes :
1. `UserInterface` : interface utilisateur graphique,
1. `CalcEngine` : réalisation de la logique de calcul.
Hacker était responsable de cette seconde classe. Elle ne devra pas changer quand la calculatrice aura une nouvelle interface.
Deux autres classes sont présentes pour vous aider à tester la calculatrice :
1. `Calculator`: programme de lancement de la calculatrice graphique
1. `CalcEngineTester` : programme de test du moteur de calcul, ce programme a été réalisé par Hacker
## Interface et documentation de `CalcEngine`
L'analyse du projet de calculatrice a abouti à définir les responsabilités de la classe `CalcEngine` sous la forme d'une liste de méthodes, dont voici la carte de description UML :
![uml.png](images/1281155122-uml.png "classe sous forme de diagramme UML")
```plantuml
@startuml
class CalcEngine {
+ clear()
+ equals()
+ getAuthor() : String
+ getDisplayValue() : int
+ getTitle() : String
+ getVersion() : String
+ minus()
+ numberPressed​(int)
+ plus()
}
@enduml
```
Une fois cette description UML transcripte dans le langage Java, la classe `CalcEngine` devrait avoir une `javadoc` associée, dont une partie est affichée ici :
![javadoc.png](images/2671621156-javadoc.png "partie résumé de la Javadoc")
\begin{comment}
<!-- ======== CONSTRUCTOR SUMMARY ======== -->
<section role="region">
<ul class="blockList">
<li class="blockList"><a id="constructor.summary">
<!-- -->
</a>
<h3>Constructor Summary</h3>
<table class="memberSummary">
<caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
<tr>
<th class="colFirst" scope="col">Constructor</th>
<th class="colLast" scope="col">Description</th>
</tr>
<tr class="altColor">
<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E()">CalcEngine</a></span>()</code></th>
<td class="colLast">
<div class="block">Create a CalcEngine instance.</div>
</td>
</tr>
</table>
</li>
</ul>
</section>
<!-- ========== METHOD SUMMARY =========== -->
<section role="region">
<ul class="blockList">
<li class="blockList"><a id="method.summary">
<!-- -->
</a>
<h3>Method Summary</h3>
<table class="memberSummary">
<caption><span id="t0" class="activeTableTab"><span>All Methods</span><span class="tabEnd">&nbsp;</span></span><span id="t2" class="tableTab"><span><a href="javascript:show(2);">Instance Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Concrete Methods</a></span><span class="tabEnd">&nbsp;</span></span></caption>
<tr>
<th class="colFirst" scope="col">Modifier and Type</th>
<th class="colSecond" scope="col">Method</th>
<th class="colLast" scope="col">Description</th>
</tr>
<tr id="i0" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#clear()">clear</a></span>()</code></th>
<td class="colLast">
<div class="block">The 'C' (clear) button was pressed.</div>
</td>
</tr>
<tr id="i1" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#equals()">equals</a></span>()</code></th>
<td class="colLast">
<div class="block">The '=' button was pressed.</div>
</td>
</tr>
<tr id="i2" class="altColor">
<td class="colFirst"><code>java.lang.String</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getAuthor()">getAuthor</a></span>()</code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr id="i3" class="rowColor">
<td class="colFirst"><code>int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getDisplayValue()">getDisplayValue</a></span>()</code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr id="i4" class="altColor">
<td class="colFirst"><code>java.lang.String</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getTitle()">getTitle</a></span>()</code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr id="i5" class="rowColor">
<td class="colFirst"><code>java.lang.String</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getVersion()">getVersion</a></span>()</code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr id="i6" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#minus()">minus</a></span>()</code></th>
<td class="colLast">
<div class="block">The '-' button was pressed.</div>
</td>
</tr>
<tr id="i7" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#numberPressed(int)">numberPressed</a></span>&#8203;(int&nbsp;number)</code></th>
<td class="colLast">
<div class="block">A number button was pressed.</div>
</td>
</tr>
<tr id="i8" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#plus()">plus</a></span>()</code></th>
<td class="colLast">
<div class="block">The '+' button was pressed.</div>
</td>
</tr>
</table>
<ul class="blockList">
<li class="blockList"><a id="methods.inherited.from.class.java.lang.Object">
<!-- -->
</a>
<h3>Methods inherited from class&nbsp;java.lang.Object</h3>
<code>clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</code></li>
</ul>
</li>
</ul>
</section>
</li>
</ul>
</div>
\end{comment}
On peut créer cette documentation avec `Maven` par la commande `mvn javadoc:javadoc` ou `mvn site`, si on a ajouté le *plugin* `JavaDoc` (https://maven.apache.org/plugins/maven-javadoc-plugin/usage.html).
Une telle interface peut être écrite sans que les méthodes soit complètement implémentées, c'est une forme de contrat entre la classe `CalcEngine` et les autres classe du projet. Cette interface doit également faire partie du **cahier des charges**, si la classe est une classe visible par le client. Pour ce projet, elle devrait typiquement être dans le cahier des charges, car le client souhaite utiliser la logique de calcul pour plusieurs projets.
## Documentation et tests
Ouvrez le projet `calculator` pour observer les classes.
Si vous regardez la classe `CalcEngine`, vous pouvez identifier les bonnes pratiques de documentation :
- Un commentaire de plusieurs lignes au début de la classe pour indiquer le but de cette classe. Vous trouvez aussi les indications d'auteur (`@author`) et de version (`@version`). Vous retrouverez ces informations dans la `javadoc`.
- Chaque méthode de l'interface a un commentaire indiquant son usage, ses paramètres (`@param`) et la valeur retournée (`@return`).
- La mise en page de la classe est consistante, la structure en bloc est bien marquée par l'indentation (vous pouvez utiliser la fonction `mise en page automatique` du menu édition), les accolades sont toujours placées de la même manière.
- Les noms de variables et d'attributs sont bien choisis.
- Les lignes ne sont pas trop longues, les expressions sont aérées.
Pour vérifier que votre programme respecte les conventions de codage vous pouvez utiliser le programme `CheckStyle` dans le menu `Outils`. Tous les IDE intègrent des outils d'analyse de code et de vérifcation des bonnes pratiques de codage, il est fortement conseillé d'activer ces vérficateurs et de respecter les consignes données pour assurer que votre programme pourra facilement évoluer.
Pour la partie **test** du programme c'est moins réjouissant, en effet Hacker a créé une classe de test de son cru, plutôt que d'utiliser le *framework* `Junit`, cela peut être une bonne idée dans certains cas notamment pour les tests d'*intégration* (quand on regroupe plusieurs classes ensemble), mais les tests de Hacker laissent faussement penser que le programme fonctionne. Pour apercevoir les dysfonctionnements il suffit pour d'exécuter les méthodes `testPlus` et `testMinus` deux fois de suite.
## Débogage
- - -
## Travail à effectuer en TP et à la maison
### Réécriture de `CalcEngineTester`
Le programme `CalcEngineTester` doit être réécrit sous forme de tests unitaires dans la classe de test `CalcEngineTest`.
### Déverminage de CalcEngine
Il y a des erreurs dans `CalcEngine`, vous devez les mettre en évidence et réaliser des tests pour pouvoir les rejouer automatiquement.
Vous devez corriger la classe `CalcEngine` pour qu'elle passse les nouveaux tests.
### Compléter les tests
Vous devez compléter les tests pour testers toutes les fonctions de l'interface.
Assurez-vous que la couverture de code est complète.
### Réécriture de `CalcEngine`
Finalement le programme de Hacker T. Largebrain contient trop d'erreurs, on vous demande de réécrire du début la classe `CalcEngine`.
Il faut reprendre la conception dès le début mais les méthodes publiques restent identiques.
Proposez une conception décrivant le fonctionnement de la calculatrice sous forme de diagramme UML ou de texte écrit. Vous pouvez trouver des exemples sur Internet.
Mettez en oeuvre votre conception en vous assurant que tous vos tests précédents passent, ajoutez en si nécessaire pour couvrir tout le code.
- - -
images/1281155122-uml.png

16.6 KiB

images/1682591866-debogueur.png

58.1 KiB

images/2090535594-calculatrice.png

18.1 KiB

images/2671621156-javadoc.png

71.1 KiB

pom.xml 0 → 100644
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.nancy.iut</groupId>
<artifactId>ProjectCalculator</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>ProjectCalculator</name>
<url>http://maven.apache.org</url>
<properties>
<maven.compiler.source>18</maven.compiler.source>
<maven.compiler.target>18</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<stylesheetfile>${basedir}/src/main/javadoc/stylesheet.css</stylesheetfile>
<show>public</show>
</configuration>
</plugin>
</plugins>
</reporting>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package fr.nancy.iut;
/**
* The main part of the calculator performing the
* arithmetic logic of the calculations.
* @author Hacker T. Largebrain
* @version 1.0
*/
public class CalcEngine
{
// The value in the display.
private int displayValue;
// The previous operator typed (+ or -).
private char previousOperator;
// The left operand to previousOperator.
private int leftOperand;
/**
* Create a CalcEngine instance.
*/
public CalcEngine()
{
displayValue = 0;
previousOperator = ' ';
leftOperand = 0;
}
/**
* @return The value currently displayed
* on the calculator.
*/
public int getDisplayValue()
{
return displayValue;
}
/**
* A number button was pressed.
* @param number The single digit.
*/
public void numberPressed(int number)
{
displayValue = displayValue * 10 + number;
}
/**
* The '+' button was pressed.
*/
public void plus()
{
applyPreviousOperator();
previousOperator = '+';
displayValue = 0;
}
/**
* The '-' button was pressed.
*/
public void minus()
{
applyPreviousOperator();
previousOperator = '-';
displayValue = 0;
}
/**
* The '=' button was pressed.
*/
public void equals()
{
if (previousOperator == '+') {
displayValue = leftOperand + displayValue;
}
else {
displayValue = leftOperand - displayValue;
}
leftOperand = 0;
}
/**
* The 'C' (clear) button was pressed.
*/
public void clear()
{
displayValue = 0;
}
/**
* @return The title of this calculation engine.
*/
public String getTitle()
{
return "Super Calculator";
}
/**
* @return The author of this engine.
*/
public String getAuthor()
{
return "Hacker T. Largebrain";
}
/**
* @return The version number of this engine.
*/
public String getVersion()
{
return "version 0.2";
}
/**
* An operator button has been pressed.
* Apply the immediately preceding operator to
* calculate an intermediate result. This will
* form the left operand of the new operator.
*/
private void applyPreviousOperator()
{
if (previousOperator == '+') {
leftOperand += displayValue;
}
else if (previousOperator == '-') {
leftOperand -= displayValue;
}
else {
// There was no preceding operator.
leftOperand = displayValue;
}
}
}
package fr.nancy.iut;
/**
* Test the CalcEngine class.
*
* @author Hacker T. Largebrain
* @version 1.0
*/
// package calculator;
public class CalcEngineTester
{
// The engine to be tested.
private CalcEngine engine;
/**
* Constructor for objects of class CalcEngineTester
*/
public CalcEngineTester()
{
engine = new CalcEngine();
}
/**
* Test everything.
*/
public void testAll()
{
System.out.println("Testing the addition operation.");
System.out.println("The result is: " + testPlus());
System.out.println("Testing the subtraction operation.");
System.out.println("The result is: " + testMinus());
System.out.println("All tests passed.");
}
/**
* Test the plus operation of the engine.
* @return the result of calculating 3+4.
*/
public int testPlus()
{
// Make sure the engine is in a valid starting state.
engine.clear();
// Simulate the key presses: 3 + 4 =
engine.numberPressed(3);
engine.plus();
engine.numberPressed(4);
engine.equals();
// Return the result, which should be 7.
return engine.getDisplayValue();
}
/**
* Test the minus operation of the engine.
* @return the result of calculating 9 - 4.
*/
public int testMinus()
{
// Make sure the engine is in a valid starting state.
engine.clear();
// Simulate the presses: 9 - 4 =
engine.numberPressed(9);
engine.minus();
engine.numberPressed(4);
engine.equals();
// Return the result, which should be 5.
return engine.getDisplayValue();
}
public static void main(String[] args) {
CalcEngineTester tester = new CalcEngineTester();
tester.testAll();
}
}
package fr.nancy.iut;
/**
* The main class of a simple calculator. Create one of these and you'll
* get the calculator on screen.
*
* @author Michael Kölling and David J. Barnes
* @version 2011.07.31
*/
public class Calculator
{
private CalcEngine engine;
private UserInterface gui;
/**
* Create a new calculator and show it.
*/
public Calculator()
{
engine = new CalcEngine();
gui = new UserInterface(engine);
}
/**
* In case the window was closed, show it again.
*/
public void show()
{
gui.setVisible(true);
}
/**
* Main program, running the Calculator GUI for CLI
* @param args No arguments
*/
public static void main(String[] args) {
(new Calculator()).show();
}
}
package fr.nancy.iut;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
/**
* A graphical user interface for the calculator. No calculation is being
* done here. This class is responsible just for putting up the display on
* screen. It then refers to the "CalcEngine" to do all the real work.
*
* @author Michael Kölling and David J. Barnes
* @version 2011.07.31
*/
public class UserInterface
implements ActionListener
{
private CalcEngine calc;
private boolean showingAuthor;
private JFrame frame;
private JTextField display;
private JLabel status;
/**
* Create a user interface.
* @param engine The calculator engine.
*/
public UserInterface(CalcEngine engine)
{
calc = engine;
showingAuthor = true;
makeFrame();
frame.setVisible(true);
}
/**
* Set the visibility of the interface.
* @param visible true if the interface is to be made visible, false otherwise.
*/
public void setVisible(boolean visible)
{
frame.setVisible(visible);
}
/**
* Make the frame for the user interface.
*/
private void makeFrame()
{
frame = new JFrame(calc.getTitle());
JPanel contentPane = (JPanel)frame.getContentPane();
contentPane.setLayout(new BorderLayout(8, 8));
contentPane.setBorder(new EmptyBorder( 10, 10, 10, 10));
display = new JTextField();
contentPane.add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel(new GridLayout(4, 4));
addButton(buttonPanel, "7");
addButton(buttonPanel, "8");
addButton(buttonPanel, "9");
addButton(buttonPanel, "C");
addButton(buttonPanel, "4");
addButton(buttonPanel, "5");
addButton(buttonPanel, "6");
addButton(buttonPanel, "?");
addButton(buttonPanel, "1");
addButton(buttonPanel, "2");
addButton(buttonPanel, "3");
buttonPanel.add(new JLabel(" "));
addButton(buttonPanel, "0");
addButton(buttonPanel, "+");
addButton(buttonPanel, "-");
addButton(buttonPanel, "=");
contentPane.add(buttonPanel, BorderLayout.CENTER);
status = new JLabel(calc.getAuthor());
contentPane.add(status, BorderLayout.SOUTH);
frame.pack();
}
/**
* Add a button to the button panel.
* @param panel The panel to receive the button.
* @param buttonText The text for the button.
*/
private void addButton(Container panel, String buttonText)
{
JButton button = new JButton(buttonText);
button.addActionListener(this);
panel.add(button);
}
/**
* An interface action has been performed.
* Find out what it was and handle it.
* @param event The event that has occured.
*/
public void actionPerformed(ActionEvent event)
{
String command = event.getActionCommand();
if(command.equals("0") ||
command.equals("1") ||
command.equals("2") ||
command.equals("3") ||
command.equals("4") ||
command.equals("5") ||
command.equals("6") ||
command.equals("7") ||
command.equals("8") ||
command.equals("9")) {
int number = Integer.parseInt(command);
calc.numberPressed(number);
}
else if(command.equals("+")) {
calc.plus();
}
else if(command.equals("-")) {
calc.minus();
}
else if(command.equals("=")) {
calc.equals();
}
else if(command.equals("C")) {
calc.clear();
}
else if(command.equals("?")) {
showInfo();
}
// else unknown command.
redisplay();
}
/**
* Update the interface display to show the current value of the
* calculator.
*/
private void redisplay()
{
display.setText("" + calc.getDisplayValue());
}
/**
* Toggle the info display in the calculator's status area between the
* author and version information.
*/
private void showInfo()
{
if(showingAuthor)
status.setText(calc.getVersion());
else
status.setText(calc.getAuthor());
showingAuthor = !showingAuthor;
}
}
package fr.nancy.iut;
import org.junit.jupiter.api.Test;
public class CalcEngineTest {
@Test
void testClear() {
}
@Test
void testEquals() {
}
@Test
void testGetAuthor() {
}
@Test
void testGetDisplayValue() {
}
@Test
void testGetTitle() {
}
@Test
void testGetVersion() {
}
@Test
void testMinus() {
}
@Test
void testNumberPressed() {
}
@Test
void testPlus() {
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment