Loquicom 1 сар өмнө
commit
0ca2a58ded
100 өөрчлөгдсөн 5640 нэмэгдсэн , 0 устгасан
  1. 19 0
      TDD2019IMPL/.classpath
  2. 6 0
      TDD2019IMPL/.gitignore
  3. 13 0
      TDD2019IMPL/.gitlab-ci.yml
  4. 9 0
      TDD2019IMPL/.gitmodules
  5. 17 0
      TDD2019IMPL/.project
  6. 11 0
      TDD2019IMPL/.settings/org.eclipse.jdt.core.prefs
  7. 95 0
      TDD2019IMPL/README.md
  8. 8 0
      TDD2019IMPL/TDD2019OWNTESTS/.classpath
  9. 1 0
      TDD2019IMPL/TDD2019OWNTESTS/.gitignore
  10. 17 0
      TDD2019IMPL/TDD2019OWNTESTS/.project
  11. 11 0
      TDD2019IMPL/TDD2019OWNTESTS/.settings/org.eclipse.jdt.core.prefs
  12. 10 0
      TDD2019IMPL/TDD2019OWNTESTS/README.md
  13. 0 0
      TDD2019IMPL/TDD2019OWNTESTS/src/.gitkeep
  14. 56 0
      TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/LispBooleanOwnTest.java
  15. 136 0
      TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/LispElementOwnTest.java
  16. 39 0
      TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/LispErrorTest.java
  17. 198 0
      TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/LispEvalOwnTest.java
  18. 41 0
      TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/LispParserOwnTest.java
  19. 34 0
      TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/REPLOwnTest.java
  20. 93 0
      TDD2019IMPL/TDD2019OWNTESTS/src/migl/util/ConsListOwnTest.java
  21. 16 0
      TDD2019IMPL/TDD2019OWNTESTS/src/migl/util/ConsOwnTest.java
  22. 8 0
      TDD2019IMPL/TDD2019TESTS/.classpath
  23. 1 0
      TDD2019IMPL/TDD2019TESTS/.gitignore
  24. 17 0
      TDD2019IMPL/TDD2019TESTS/.project
  25. 11 0
      TDD2019IMPL/TDD2019TESTS/.settings/org.eclipse.jdt.core.prefs
  26. 7 0
      TDD2019IMPL/TDD2019TESTS/README.md
  27. 48 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/EvalTest.java
  28. 64 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/JschemeEval.java
  29. 50 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/LispEval.java
  30. 132 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/basic_lisp_operators.story
  31. 84 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/basic_operators.story
  32. 118 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-bonus-math_operators.story
  33. 42 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-magniez.story
  34. 23 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-sem8-list_manipulation.story
  35. 184 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-sem8-simplecontext.story
  36. 116 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-sem9-advancedcontext.story
  37. 44 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-sem9-jscheme_behavior.story
  38. 22 0
      TDD2019IMPL/TDD2019TESTS/src/migl/bdd/more_operator_tests.story
  39. 13 0
      TDD2019IMPL/TDD2019TESTS/src/migl/lisp/AbstractTDD.java
  40. 109 0
      TDD2019IMPL/TDD2019TESTS/src/migl/lisp/LispParserTest.java
  41. 118 0
      TDD2019IMPL/TDD2019TESTS/src/migl/lisp/MoreLispParserTest.java
  42. 34 0
      TDD2019IMPL/TDD2019TESTS/src/migl/lisp/ReplTest.java
  43. 108 0
      TDD2019IMPL/TDD2019TESTS/src/migl/util/ConsListTest.java
  44. 94 0
      TDD2019IMPL/TDD2019TESTS/src/migl/util/ConsTest.java
  45. 156 0
      TDD2019IMPL/TDD2019TESTS/src/migl/util/MoreConsListTest.java
  46. 148 0
      TDD2019IMPL/build.xml
  47. 18 0
      TDD2019IMPL/checklinks.sh
  48. BIN
      TDD2019IMPL/lib/commons-codec-1.11.jar
  49. BIN
      TDD2019IMPL/lib/commons-collections4-4.1.jar
  50. BIN
      TDD2019IMPL/lib/commons-io-2.5.jar
  51. BIN
      TDD2019IMPL/lib/commons-lang3-3.5.jar
  52. BIN
      TDD2019IMPL/lib/freemarker.jar
  53. BIN
      TDD2019IMPL/lib/hamcrest-core-1.3.jar
  54. BIN
      TDD2019IMPL/lib/jacocoant.jar
  55. BIN
      TDD2019IMPL/lib/jbehave-ant-4.1.jar
  56. BIN
      TDD2019IMPL/lib/jbehave-core-4.1-javadoc.jar
  57. BIN
      TDD2019IMPL/lib/jbehave-core-4.1.jar
  58. BIN
      TDD2019IMPL/lib/jbehave-junit-runner-1.2.1-20150529.081438-4.jar
  59. BIN
      TDD2019IMPL/lib/jscheme-7.2.jar
  60. BIN
      TDD2019IMPL/lib/junit-4.12.jar
  61. BIN
      TDD2019IMPL/lib/org.eclipse.jdt.annotation_2.1.100.v20170511-1408.jar
  62. BIN
      TDD2019IMPL/lib/paranamer-2.8.jar
  63. BIN
      TDD2019IMPL/lib/pitest-1.4.5.jar
  64. BIN
      TDD2019IMPL/lib/pitest-ant-1.4.5.jar
  65. BIN
      TDD2019IMPL/lib/pitest-entry-1.4.5.jar
  66. BIN
      TDD2019IMPL/lib/plexus-utils-3.0.24.jar
  67. BIN
      TDD2019IMPL/lib/qualinsight-plugins-sonarqube-smell-api-4.0.0.jar
  68. BIN
      TDD2019IMPL/lib/sonarqube-ant-task-2.5.jar
  69. BIN
      TDD2019IMPL/org.eclipse.jdt.annotation_2.2.200.v20180921-1416.jar
  70. 45 0
      TDD2019IMPL/src/migl/lisp/Lisp.java
  71. 90 0
      TDD2019IMPL/src/migl/lisp/LispBoolean.java
  72. 276 0
      TDD2019IMPL/src/migl/lisp/LispElement.java
  73. 64 0
      TDD2019IMPL/src/migl/lisp/LispError.java
  74. 407 0
      TDD2019IMPL/src/migl/lisp/LispEval.java
  75. 39 0
      TDD2019IMPL/src/migl/lisp/LispFactory.java
  76. 40 0
      TDD2019IMPL/src/migl/lisp/LispImpl.java
  77. 139 0
      TDD2019IMPL/src/migl/lisp/LispList.java
  78. 224 0
      TDD2019IMPL/src/migl/lisp/LispParser.java
  79. 44 0
      TDD2019IMPL/src/migl/lisp/REPL.java
  80. 50 0
      TDD2019IMPL/src/migl/lisp/operator/ComparatorOperator.java
  81. 79 0
      TDD2019IMPL/src/migl/lisp/operator/ConsOperator.java
  82. 247 0
      TDD2019IMPL/src/migl/lisp/operator/DefineOperator.java
  83. 26 0
      TDD2019IMPL/src/migl/lisp/operator/LispOperator.java
  84. 38 0
      TDD2019IMPL/src/migl/lisp/operator/MathOperator.java
  85. 63 0
      TDD2019IMPL/src/migl/lisp/operator/MinMaxOperator.java
  86. 117 0
      TDD2019IMPL/src/migl/util/Cons.java
  87. 76 0
      TDD2019IMPL/src/migl/util/ConsEmptyList.java
  88. 109 0
      TDD2019IMPL/src/migl/util/ConsList.java
  89. 65 0
      TDD2019IMPL/src/migl/util/ConsListFactory.java
  90. 109 0
      TDD2019IMPL/src/migl/util/ConsListImpl.java
  91. 8 0
      TDD2019OWNTESTS/.classpath
  92. 1 0
      TDD2019OWNTESTS/.gitignore
  93. 17 0
      TDD2019OWNTESTS/.project
  94. 11 0
      TDD2019OWNTESTS/.settings/org.eclipse.jdt.core.prefs
  95. 10 0
      TDD2019OWNTESTS/README.md
  96. 0 0
      TDD2019OWNTESTS/src/.gitkeep
  97. 56 0
      TDD2019OWNTESTS/src/migl/lisp/LispBooleanOwnTest.java
  98. 245 0
      TDD2019OWNTESTS/src/migl/lisp/LispElementOwnTest.java
  99. 39 0
      TDD2019OWNTESTS/src/migl/lisp/LispErrorTest.java
  100. 307 0
      TDD2019OWNTESTS/src/migl/lisp/LispEvalOwnTest.java

+ 19 - 0
TDD2019IMPL/.classpath

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
+	<classpathentry kind="lib" path="org.eclipse.jdt.annotation_2.2.200.v20180921-1416.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jbehave-core-4.1-javadoc.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jbehave-core-4.1.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jbehave-junit-runner-1.2.1-20150529.081438-4.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jscheme-7.2.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/paranamer-2.8.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/commons-codec-1.11.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/commons-collections4-4.1.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/commons-io-2.5.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/commons-lang3-3.5.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/plexus-utils-3.0.24.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/freemarker.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

+ 6 - 0
TDD2019IMPL/.gitignore

@@ -0,0 +1,6 @@
+bin
+.sonar
+build
+testreports
+src/test
+.directory

+ 13 - 0
TDD2019IMPL/.gitlab-ci.yml

@@ -0,0 +1,13 @@
+variables:
+  GIT_SUBMODULE_STRATEGY: recursive
+
+before_script: 
+   - "./checklinks.sh $CI_PROJECT_NAMESPACE"
+   - "git submodule update --remote --init"
+
+tests:
+   script: "ant -Detudiant=$CI_PROJECT_NAMESPACE sonar"
+   artifacts:
+     untracked: true
+   tags: 
+     - java

+ 9 - 0
TDD2019IMPL/.gitmodules

@@ -0,0 +1,9 @@
+[submodule "TDD2019TESTS"]
+	path = TDD2019TESTS
+	url = ../../m1-2018-2019/TDD2019TESTS.git
+[submodule "TDD2019OWNTESTS"]
+	path = TDD2019OWNTESTS
+	url = https://forge.univ-artois.fr/arthur_brandao/TDD2019OWNTESTS.git
+[submodule "TDD2019HIDDENTESTS"]
+	path = TDD2019HIDDENTESTS
+	url = https://forge.univ-artois.fr/root/TDD2019HIDDENTESTS.git

+ 17 - 0
TDD2019IMPL/.project

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>TDD2019IMPL</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

+ 11 - 0
TDD2019IMPL/.settings/org.eclipse.jdt.core.prefs

@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8

+ 95 - 0
TDD2019IMPL/README.md

@@ -0,0 +1,95 @@
+# Projet interpréteur lisp
+
+[![Qualité](https://forge.univ-artois.fr/sonar67/api/badges/gate?key=arthur_brandao%3A2019%3AMyLisp)](https://forge.univ-artois.fr/sonar67/dashboard/index/arthur_brandao%3A2019%3AMyLisp)
+[![Tests réussis](https://forge.univ-artois.fr/sonar67/api/badges/measure?key=arthur_brandao%3A2019%3AMyLisp&metric=test_success_density)](https://forge.univ-artois.fr/sonar67/dashboard/index/arthur_brandao%3A2019%3AMyLisp)
+[![Couverture de code](https://forge.univ-artois.fr/sonar67/api/badges/measure?key=arthur_brandao%3A2019%3AMyLisp&metric=coverage)](https://forge.univ-artois.fr/sonar67/dashboard/index/arthur_brandao%3A2019%3AMyLisp)
+
+[*Voir sur SonarQube*](https://forge.univ-artois.fr/sonar67/dashboard?id=arthur_brandao%3A2019%3AMyLisp)
+
+La page [Lisp sur wikipedia](https://en.wikipedia.org/wiki/Lisp_%28programming_language%29) et la page [Scheme sur wikipedia](https://en.wikipedia.org/wiki/Scheme_%28programming_language%29) fournissent l'historique et les fonctionnalités du langage.
+
+Le comportement de l'interpréteur (le tests) sont validés à l'aide de l'interpréteur [JScheme](http://jscheme.sourceforge.net/jscheme/main.html).
+
+Le nombre de tests augmentera au cours du semestre jusqu'à obtenir un interpréteur pleinement fonctionnel.
+
+Ce projet est basé sur le travail de [Peter Norvig en Python](http://norvig.com/lispy.html).
+
+Peter Norvig a aussi proposé une version [Java de son interpréteur](http://norvig.com/jscheme.html). Cette version a été conçue à la naissance du langage, et ne peut pas être considérée comme une conception oriénté objet d'un interpréteur Lisp.
+
+Plus récemment, [une version Java a été proposée par Remy Forax](https://forax.github.io/2014-06-01-e733e6af6114eff55149-lispy_in_java.html). 
+Si cette solution utilise des concepts avancés et récents de Java (lambdas et streams), le code reste proche de la version python, donc pas vraiment orienté objet.
+
+On pourrait imaginer, dans un futur proche, passer de la réalisation d'un simple interpréteur à [un système d'exploitation complet](http://metamodular.com/lispos.pdf).
+
+## Pour déclarer ce projet comme source `upstream`
+
+Il suffit de déclarer une fois ce projet comme dépôt distant de votre fork :
+
+```shell
+$ git remote add upstream https://forge.univ-artois.fr/m1-2018-2019/TDD2019IMPL.git
+```
+
+Ensuite, à chaque mise à jour de ce projet, vous pouvez mettre à jour votre fork
+à l'aide des commandes suivantes :
+
+```shell
+$ git pull upstream master
+$ git push
+```
+
+## Si vous ne voyez plus vos tests dans votre projet
+
+Il suffit de rajouter le projet de tests comme un sous module du projet :
+
+```shell
+$ git submodule add https://forge.univ-artois.fr/m1-2018-2019/TDD2019TESTS.git
+# remplacer le chemin absolu https://forge.univ-artois.fr/m1-2018-2019/TDD2019TESTS.git 
+# par ../../m1-2018-2019/TDD2019TESTS.git dans le fichier `.gitmodules`.
+$ git commit -m "Les tests sont de retour"
+$ git push
+```
+
+## Commandes submodule (Lien vers les git des tests)
+
+Pour mettre à jour les submodules :
+
+```shell
+$ git submodule update --remote
+```
+
+Pour mettre à jour un submodule précis :
+
+```sh
+$ git submodule update --remote <nom_dossier_submodule>
+```
+
+
+
+## Note à propos de PiTest
+
+Avec la configuration par defaut du build.xml :
+
+```xml
+<!-- ligne 114 -->
+<target name="m1" description="Verification des projets de TDD2019" depends="clean,build,tests,mutationCoverage" />
+
+<!-- Define the SonarQube target -->
+<target name="sonar" depends="m1" description="Analyse le code avec SonarQube">
+```
+
+La commande `ant -Detudiant=prenom_nom sonar` (qui est utilisé pour valider le code dans l'intégration continue de Gitlab), ne va pas lancer les tests sonar si tous les tests unitaires ne passent pas (ce qui peut être gênant). Ceci est causé par la dépendance qu'a sonar vers m1 et m1 vers mutationCoverage. Si tous les tests unitaires ne sont pas passés alors PiTest (mutationCoverage) va échouer, hors comme sa dépendance échoue, m1 échoue. Donc sonar ne se lance pas car sa dépendance à échoué.
+
+Pour résoudre le problème j'ai déplacé le test de mutation. Il n'est plus exécuté en tant que dépendance de m1, mais en tant que subant. Ce qui permet en cas d'erreur de ne pas faire échouer m1 et donc permettre de lancer sonar. Le nouveau code est le suivant.
+
+```xml
+<!-- ligne 114 -->
+<target name="m1" description="Verification des projets de TDD2019" depends="clean,build,tests">
+	<subant failonerror="false" target="mutationCoverage">
+		<fileset dir="." includes="build.xml" />
+	</subant>
+</target>
+
+<!-- Define the SonarQube target -->
+<target name="sonar" depends="m1" description="Analyse le code avec SonarQube">
+```
+

+ 8 - 0
TDD2019IMPL/TDD2019OWNTESTS/.classpath

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/TDD2019IMPL"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

+ 1 - 0
TDD2019IMPL/TDD2019OWNTESTS/.gitignore

@@ -0,0 +1 @@
+bin

+ 17 - 0
TDD2019IMPL/TDD2019OWNTESTS/.project

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>TDD2019OWNTESTS</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

+ 11 - 0
TDD2019IMPL/TDD2019OWNTESTS/.settings/org.eclipse.jdt.core.prefs

@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8

+ 10 - 0
TDD2019IMPL/TDD2019OWNTESTS/README.md

@@ -0,0 +1,10 @@
+# Tests unitaires et d'acceptance supplémentaires
+
+Ces tests seront utilisés pour votre projet seulement, pour compléter
+les tests publics et les tests cachés, pour augmenter la couverture
+de votre code par les tests.
+
+Pour ajouter des tests spécifiques à votre projet, vous devez simplement
+"forker" ce projet.
+
+Il vous suffit ensuite de rajouter des fichiers de tests à ce projet.

+ 0 - 0
TDD2019IMPL/TDD2019OWNTESTS/src/.gitkeep


+ 56 - 0
TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/LispBooleanOwnTest.java

@@ -0,0 +1,56 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+public class LispBooleanOwnTest {
+	
+	@Test
+	public void testLispBooleanValue(){
+		assertTrue(LispBoolean.TRUE.value());
+		assertFalse(LispBoolean.FALSE.value());
+	}
+	
+	@Test
+	public void testLispBooleanToString() {
+		assertEquals("#t", LispBoolean.TRUE.toString());
+		assertEquals("#f", LispBoolean.FALSE.toString());
+	}
+	
+	@Test
+	public void testLispBooleanValueOfBoolean() {
+		assertEquals(LispBoolean.TRUE, LispBoolean.valueOf(true));
+		assertEquals(LispBoolean.FALSE, LispBoolean.valueOf(false));
+	}
+	
+	@Test
+	public void testLispBooleanHashCode() {
+		assertEquals(new Boolean(true).hashCode(), LispBoolean.TRUE.hashCode());
+		assertEquals(new Boolean(false).hashCode(), LispBoolean.FALSE.hashCode());
+		Map<LispBoolean, String> map = new HashMap<>();
+		map.put(LispBoolean.TRUE, "#t");
+		map.put(LispBoolean.FALSE, "#f");
+		assertEquals("#t", map.get(LispBoolean.TRUE));
+		assertEquals("#f", map.get(LispBoolean.FALSE));
+	}
+	
+	@Test
+	public void testLisbBooleanEquals() {
+		assertTrue(LispBoolean.TRUE.equals(LispBoolean.TRUE));
+		assertFalse(LispBoolean.TRUE.equals(LispBoolean.FALSE));
+		assertTrue(LispBoolean.FALSE.equals(LispBoolean.FALSE));
+		assertTrue(LispBoolean.TRUE.equals(LispBoolean.valueOf(true)));
+		assertTrue(LispBoolean.FALSE.equals(LispBoolean.valueOf(false)));
+		assertTrue(LispBoolean.TRUE.equals(LispBoolean.valueOf("#t")));
+		assertTrue(LispBoolean.FALSE.equals(LispBoolean.valueOf("#f")));
+		assertFalse(LispBoolean.TRUE.equals(new Boolean(true)));
+		assertFalse(LispBoolean.FALSE.equals(new Boolean(false)));
+	}
+
+}

+ 136 - 0
TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/LispElementOwnTest.java

@@ -0,0 +1,136 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigInteger;
+import java.util.Map;
+import java.util.HashMap;
+
+import org.junit.Test;
+
+public class LispElementOwnTest {
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testGenerateBadElement() {
+		Object obj = new Object();
+		LispElement.generate(obj);
+	}
+	
+	@Test(expected = IllegalStateException.class)
+	public void testToIntFail() {
+		LispElement elt = LispElement.valueOf("5.8");
+		elt.toInt();
+	}
+	
+	@Test(expected = IllegalStateException.class)
+	public void testToNumberFail() {
+		LispElement elt = LispElement.valueOf("test");
+		elt.toNumber();
+	}
+	
+	@Test(expected = IllegalStateException.class)
+	public void testToBooleanFail() {
+		LispElement elt = LispElement.valueOf("5.8");
+		elt.toBoolean();
+	}
+	
+	@Test(expected = IllegalStateException.class)
+	public void testToStrFail() {
+		LispElement elt = LispElement.valueOf("5.8");
+		elt.toStr();
+	}
+	
+	@Test
+	public void testToInt() {
+		LispElement elt = LispElement.valueOf("8888888888888888");
+		BigInteger expected = new BigInteger("8888888888888888");
+		assertEquals(expected, elt.toInt());
+	}
+	
+	@Test
+	public void testToNumberFromDouble() {
+		LispElement elt = LispElement.valueOf("5.8");
+		Double expected = Double.valueOf(5.8);
+		Double value = elt.toNumber();
+		assertEquals(expected, value);
+	}
+	
+	@Test
+	public void testToNumberFromInt() {
+		LispElement elt = LispElement.valueOf("8");
+		Double expected = Double.valueOf(8.0);
+		Integer notExpected = 8;
+		assertEquals(expected, (Double) elt.toNumber());
+		assertNotEquals(notExpected, elt.toNumber());
+	}
+	
+	@Test
+	public void testToBoolean() {
+		LispElement elt1 = LispElement.valueOf("#t");
+		LispElement elt2 = LispElement.generate(false);
+		assertTrue(elt1.toBoolean());
+		assertFalse(elt2.toBoolean());
+	}
+	
+	@Test
+	public void testToStr() {
+		LispElement elt1 = LispElement.valueOf("test");
+		LispElement elt2 = LispElement.valueOf("test ");
+		assertEquals("test", elt1.toStr());
+		assertNotEquals("test", elt2.toStr());
+	}
+	
+	@Test
+	public void testHashCode() {
+		LispElement elt1 = LispElement.valueOf("test");
+		LispElement elt2 = LispElement.valueOf("#t");
+		LispElement elt3 = LispElement.valueOf("8");
+		LispElement elt4 = LispElement.valueOf("8.0");
+		Map<LispElement, String> map = new HashMap<>();
+		map.put(elt1, "elt1");
+		map.put(elt2, "elt2");
+		map.put(elt3, "elt3");
+		map.put(elt4, "elt4");
+		assertEquals("elt1", map.get(elt1));
+		assertEquals("elt2", map.get(elt2));
+		assertEquals("elt3", map.get(elt3));
+		assertEquals("elt4", map.get(elt4));
+	}
+	
+	@Test
+	public void testEquals() {
+		LispElement elt1 = LispElement.valueOf("test");
+		LispElement elt2 = LispElement.valueOf("test");
+		LispElement elt3 = LispElement.valueOf("Test");
+		LispElement elt4 = LispElement.valueOf("#t");
+		LispElement elt5 = LispElement.valueOf("#t");
+		LispElement elt6 = LispElement.valueOf("#f");
+		LispElement elt7 = LispElement.valueOf("8");
+		LispElement elt8 = LispElement.valueOf("8.0");
+		Object other = new Object();
+		assertTrue(elt1.equals(elt2));
+		assertFalse(elt1.equals(elt3));
+		assertTrue(elt1.equals(elt1));
+		assertFalse(elt1.equals(null));
+		assertFalse(elt1.equals(elt4));
+		assertTrue(elt4.equals(elt5));
+		assertFalse(elt4.equals(elt6));
+		assertFalse(elt7.equals(elt8));
+		assertFalse(elt1.equals(other));
+		assertEquals(elt1.hashCode(), elt2.hashCode());
+		assertNotEquals(elt1.hashCode(), elt3.hashCode());
+		assertEquals(elt4.hashCode(), elt5.hashCode());
+		assertNotEquals(elt4.hashCode(), elt6.hashCode());
+		assertNotEquals(elt7.hashCode(), elt8.hashCode());
+	}
+
+	@Test
+	public void testGenerateBigIntFromInt() {
+		LispElement elt = LispElement.generate(Integer.valueOf(8));
+		BigInteger expected = new BigInteger("8");
+		assertEquals(expected, elt.value);
+	}
+}

+ 39 - 0
TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/LispErrorTest.java

@@ -0,0 +1,39 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class LispErrorTest {
+
+	@Test
+	public void testLispErrorMessageCause() {
+		Throwable cause = new IllegalArgumentException();
+		try {
+			throw new LispError("Erreur test", cause);
+		} catch (LispError ex) {
+			assertEquals("Erreur test", ex.getMessage());
+			assertEquals(cause, ex.getCause());
+		}
+	}
+	
+	@Test
+	public void testLispErrorMessage() {
+		try {
+			throw new LispError("Erreur test");
+		} catch (LispError ex) {
+			assertEquals("Erreur test", ex.getMessage());
+		}
+	}
+	
+	@Test
+	public void testLispErrorCause() {
+		Throwable cause = new IllegalArgumentException();
+		try {
+			throw new LispError(cause);
+		} catch (LispError ex) {
+			assertEquals(cause, ex.getCause());
+		}
+	}
+	
+}

+ 198 - 0
TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/LispEvalOwnTest.java

@@ -0,0 +1,198 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.math.BigInteger;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import migl.lisp.operator.ComparatorOperator;
+import migl.util.ConsList;
+import migl.util.ConsListFactory;
+
+public class LispEvalOwnTest {
+
+	private Lisp interpreter;
+
+	@Before
+	public void init() {
+		interpreter = LispFactory.makeIntepreter();
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentNot() throws LispError {
+		interpreter.evaluate(interpreter.parse("(not #t #f"));
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentAnd() throws LispError {
+		interpreter.evaluate(interpreter.parse("(and #t"));
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentSup() throws LispError {
+		interpreter.evaluate(interpreter.parse("(> #t"));
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentSupEqu() throws LispError {
+		interpreter.evaluate(interpreter.parse("(>= #f"));
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentInf() throws LispError {
+		interpreter.evaluate(interpreter.parse("(< #t"));
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentInfEqu() throws LispError {
+		interpreter.evaluate(interpreter.parse("(<= #f"));
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentEqu() throws LispError {
+		interpreter.evaluate(interpreter.parse("(= #t"));
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentSubstract() throws LispError {
+		interpreter.evaluate(interpreter.parse("(- 8 5 4"));
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentSubstract2() throws LispError {
+		interpreter.evaluate(interpreter.parse("(-)"));
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentDivide() throws LispError {
+		interpreter.evaluate(interpreter.parse("(/ 8)"));
+	}
+
+	@Test
+	public void testEvaluateSingleton() throws LispError {
+		Object elt = interpreter.parse("8");
+		assertEquals(LispElement.generate(8), interpreter.evaluate(elt));
+	}
+	
+	@Test(expected = LispError.class)
+	public void testUnknowOperator() throws LispError {
+		interpreter.evaluate(interpreter.parse("(gl2 #t)"));
+	}
+	
+	@Test(expected = LispError.class)
+	public void testMalformedList() throws LispError {
+		ConsList<Object> list = ConsListFactory.nil();
+		list = list.prepend(new Object()).prepend("not");
+		interpreter.evaluate(list);
+	}
+	
+	@Test
+	public void testOriginUnknowOperatorException() {
+		try {
+			interpreter.evaluate(interpreter.parse("(gl2 #t)"));
+			fail("No exception thrown");
+		} catch (LispError ex) {
+			assertTrue(ex.getCause() instanceof UnsupportedOperationException);
+		}
+	}
+	
+	@Test
+	public void testOriginMalformedListException() {
+		ConsList<Object> list = ConsListFactory.nil();
+		list = list.prepend(new Object()).prepend("not");
+		try {
+			interpreter.evaluate(list);
+			fail("No exception thrown");
+		} catch (LispError ex) {
+			assertTrue(ex.getCause() instanceof IllegalArgumentException);
+		}
+	}
+	
+	@Test
+	public void testOriginBadArgumentTypeException() {
+		try {
+			interpreter.evaluate(interpreter.parse("(not 8)"));
+			fail("No exception thrown");
+		} catch (LispError ex) {
+			assertTrue(ex.getCause() instanceof IllegalStateException);
+		}
+	}
+	
+	@Test(expected = LispError.class)
+	public void testEvaluateIncorrectObject() throws LispError {
+		interpreter.evaluate(interpreter);
+	}
+	
+	@Test
+	public void testSubList() throws LispError {
+		LispElement expected = LispElement.generate(9.8);
+		LispElement result = (LispElement) interpreter.evaluate(interpreter.parse("(+ (- 8 4.2) (* 2 3))"));
+		assertEquals(expected, result);
+	}
+	
+	@Test
+	public void testOperators1() throws LispError {
+		assertEquals(LispElement.generate(true), interpreter.eval("(not #f)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(not #t)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(and #t #t)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(and #f #t)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(or #f #t)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(or #f #f)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(> 8 5)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(> 8 8)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(> 5 8)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(>= 8 5)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(>= 8 8)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(>= 5 8)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(< 5 8)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(< 8 8)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(< 8 5)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(<= 5 8)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(<= 8 8)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(<= 8 5)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(= 8 8)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(= 8 5)"));
+		assertEquals(LispElement.generate(8), interpreter.eval("(+ 5 3)"));
+		assertEquals(LispElement.generate(8.4), interpreter.eval("(+ 5 3.4)"));
+		assertEquals(LispElement.generate(8.8), interpreter.eval("(+ 4.4 4.4)"));
+		assertEquals(LispElement.generate(8.0), interpreter.eval("(+ 4 4 0.0)"));
+		assertEquals(LispElement.generate(16), interpreter.eval("(* 4 2 2)"));
+		assertEquals(LispElement.generate(8.0), interpreter.eval("(* 4.0 2)"));
+		assertEquals(LispElement.generate(10.0), interpreter.eval("(* 2.0 5.0)"));
+		assertEquals(LispElement.generate(-8), interpreter.eval("(- 8)"));
+		assertEquals(LispElement.generate(-8.4), interpreter.eval("(- 8.4)"));
+		assertEquals(LispElement.generate(8), interpreter.eval("(- 16 8)"));
+		assertEquals(LispElement.generate(10.0), interpreter.eval("(- 18.0 8)"));
+		assertEquals(LispElement.generate(2.0), interpreter.eval("(- 10.0 8.0)"));
+		assertEquals(LispElement.generate(2), interpreter.eval("(/ 8 4)"));
+		assertEquals(LispElement.generate(4.0), interpreter.eval("(/ 12 3.0)"));
+		assertEquals(LispElement.generate(10.0), interpreter.eval("(/ 80.0 8.0)"));
+	}
+	
+	@Test
+	public void testOperators2( ) throws LispError {
+		assertEquals(LispElement.generate("(+ 8 4)"), interpreter.eval("(quote (+ 8 4))"));
+		assertEquals(LispElement.generate(4.2), interpreter.eval("(if #f 8 4.2)"));
+		assertEquals(LispElement.generate(8), interpreter.eval("(if #t 8 4.2)"));
+		assertEquals(LispElement.generate(-11), interpreter.eval("(- 9 (* 4 5))"));
+		assertEquals(LispElement.generate("(4 . 8)"), interpreter.eval("(cons 4 8)"));
+		assertEquals(LispElement.generate("(())"), interpreter.eval("(cons () ())"));
+		assertEquals(LispElement.generate("(8)"), interpreter.eval("(cons 8 ())"));
+		assertEquals(LispElement.generate("(() . 8)"), interpreter.eval("(cons () 8)"));
+		assertEquals(LispElement.generate("(8 4)"), interpreter.eval("(cons 8 (cons 4 ()))"));
+	}
+	
+	@Test(expected = LispError.class)
+	public void testComparatorOperatorException() throws LispError {
+		LispOperator comp = new ComparatorOperator();
+		ConsList<Object> cl = ConsListFactory.nil();
+		cl = cl.prepend(new BigInteger("8"));
+		cl = cl.prepend(4.2);
+		comp.apply("_", cl);
+	}
+
+}

+ 41 - 0
TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/LispParserOwnTest.java

@@ -0,0 +1,41 @@
+package migl.lisp;
+
+import static org.junit.Assert.fail;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class LispParserOwnTest {
+
+	private Lisp lisp;
+	
+	@Before
+	public void init(){
+		lisp = LispFactory.makeIntepreter();
+	}
+	
+	@Test(expected = LispError.class)
+	public void testMultiElementParser() throws LispError {
+		lisp.parse("10 str");
+	}
+	
+	@Test
+	public void testExplode() {
+		try {
+			lisp.parse("(aze (10 5.8))");
+		} catch (LispError e) {
+			fail("Erreur pendant l'analyse");
+		}
+	}
+	
+	@Test(expected = LispError.class)
+	public void testBadEndList() throws LispError {
+		lisp.parse("(aze 158 8.6");
+	}
+	
+	@Test(expected = LispError.class)
+	public void testListandElementAfter() throws LispError {
+		lisp.parse("(aze (aze rty)) aze");
+	}
+
+}

+ 34 - 0
TDD2019IMPL/TDD2019OWNTESTS/src/migl/lisp/REPLOwnTest.java

@@ -0,0 +1,34 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class REPLOwnTest {
+
+	private ByteArrayOutputStream myout;
+
+    @Before
+    public void setUp() {
+        myout = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(myout));
+    }
+
+    @Test
+    public void test() {
+        String sep = System.lineSeparator();
+        ByteArrayInputStream myin = new ByteArrayInputStream(("+ 1 2" + sep + "quit" + sep).getBytes());
+        System.setIn(myin);
+        REPL.main(new String[] {});
+        assertEquals("My super own Lisp/Scheme interpreter 2019" + sep
+                + "Enter a valid Lisp expression followed by Enter. type 'quit' to exit." + sep + "> " +  "Error: " + "Invalid Format" + sep
+                + "> " + "Bye." + sep, myout.toString());
+
+    }
+	
+}

+ 93 - 0
TDD2019IMPL/TDD2019OWNTESTS/src/migl/util/ConsListOwnTest.java

@@ -0,0 +1,93 @@
+package migl.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ConsListOwnTest {
+	
+	private ConsList<Integer> list;
+
+	@Before
+	public void init() {
+		list = ConsListFactory.nil();
+	}
+	
+	@Test
+	public void testConsListImplEquals() {
+		ConsList<Integer> list2 = ConsListFactory.asList(8, 88);
+		ConsList<Integer> list3 = ConsListFactory.asList(88, 8);
+		list = list.prepend(88).prepend(8);
+		assertTrue(list.equals(list));
+		assertTrue(list.equals(list2));
+		assertFalse(list.equals(list3));
+		assertFalse(list.equals(null));
+		assertTrue(list.equals(ConsListFactory.asList(8, 88)));
+		assertTrue(list.equals(ConsListFactory.singleton(88).prepend(8)));
+		assertFalse(list.equals(ConsListFactory.singleton(88).prepend(888)));
+		assertEquals(list.hashCode(), list2.hashCode());
+		assertNotEquals(list.hashCode(), list3.hashCode());
+	}
+	
+	@Test
+	public void testConsListImplHashCode() {
+		ConsList<Integer> list2 = ConsListFactory.asList(8, 888);
+		ConsList<Integer> list3 = ConsListFactory.asList(88, 8);
+		list = list.prepend(88).prepend(8);
+		Map<ConsList<Integer>, String> map = new HashMap<>();
+		map.put(list, "L1");
+		map.put(list2, "L2");
+		map.put(list3, "L3");
+		assertEquals("L1", map.get(list));
+		assertEquals("L2", map.get(list2));
+		assertEquals("L3", map.get(list3));
+	}
+
+	@Test
+	public void testAsListEmpty() {
+		ConsList<Integer> list2 = ConsListFactory.asList();
+		assertEquals(list, list2);
+	}
+	
+	@Test
+	public void testAsListSingleton() {
+		ConsList<Integer> list1 = ConsListFactory.singleton(8);
+		ConsList<Integer> list2 = ConsListFactory.asList(8);
+		assertEquals(list1, list2);
+	}
+	
+	@Test
+	public void testConsEmptyListMap() {
+		ConsList<String> list2 = ConsListFactory.nil();
+		assertEquals(list2, list.map(p -> Integer.valueOf(p)));
+	}
+	
+	@Test
+	public void testIsEmpty() {
+		assertTrue(list.isEmpty());
+		assertEquals(list.size(), 0);
+		list = list.prepend(8);
+		assertFalse(list.isEmpty());
+		assertNotEquals(list.size(), 0);
+	}
+	
+	@Test(expected = IllegalArgumentException.class)
+    public void testCreateEmptyConsListImpl() {
+        list = new ConsListImpl<Integer>(null, null);
+    }
+	
+	@Test
+	public void testListWithNull() {
+		list = list.prepend(null);
+		assertEquals(1, list.size());
+		assertEquals("(null)", list.toString());
+	}
+	
+}

+ 16 - 0
TDD2019IMPL/TDD2019OWNTESTS/src/migl/util/ConsOwnTest.java

@@ -0,0 +1,16 @@
+package migl.util;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class ConsOwnTest {
+
+	@Test
+	public void testEquals() {
+		Cons<String, String> c1 = new Cons<>(null, "str");
+		Cons<String, String> c2 = new Cons<>("not null", "str");
+		assertFalse(c1.equals(c2));
+	}
+
+}

+ 8 - 0
TDD2019IMPL/TDD2019TESTS/.classpath

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/TDD2019IMPL"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

+ 1 - 0
TDD2019IMPL/TDD2019TESTS/.gitignore

@@ -0,0 +1 @@
+/bin

+ 17 - 0
TDD2019IMPL/TDD2019TESTS/.project

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>TDD2019TESTS</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

+ 11 - 0
TDD2019IMPL/TDD2019TESTS/.settings/org.eclipse.jdt.core.prefs

@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8

+ 7 - 0
TDD2019IMPL/TDD2019TESTS/README.md

@@ -0,0 +1,7 @@
+# Les tests du projet de GL2
+
+Ce projet a vocation à évoluer au cours du semestre : de nouveaux tests
+seront ajoutés chaque semaine.
+
+Vous avez la possibilité de proposer des tests additionnels à l'aide de MR,
+comme au premier semestre.

+ 48 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/EvalTest.java

@@ -0,0 +1,48 @@
+package migl.bdd;
+
+import static org.jbehave.core.io.CodeLocations.codeLocationFromClass;
+
+import java.util.List;
+
+import org.jbehave.core.configuration.Configuration;
+import org.jbehave.core.configuration.MostUsefulConfiguration;
+import org.jbehave.core.io.StoryFinder;
+import org.jbehave.core.junit.JUnitStories;
+import org.jbehave.core.reporters.Format;
+import org.jbehave.core.reporters.StoryReporterBuilder;
+import org.jbehave.core.steps.InjectableStepsFactory;
+import org.jbehave.core.steps.InstanceStepsFactory;
+import org.junit.Test;
+
+public class EvalTest extends JUnitStories {
+
+    public EvalTest() {
+        configuredEmbedder().embedderControls().doGenerateViewAfterStories(false).doIgnoreFailureInStories(false)
+                .doIgnoreFailureInView(false).doVerboseFailures(true);
+    }
+
+    @Override
+    public Configuration configuration() {
+        return new MostUsefulConfiguration()
+                // CONSOLE reporting
+                .useStoryReporterBuilder(new StoryReporterBuilder().withDefaultFormats().withFormats(Format.CONSOLE));
+    }
+
+    // Here we specify the steps classes
+    @Override
+    public InjectableStepsFactory stepsFactory() {
+        // varargs, can have more that one steps classes
+        return new InstanceStepsFactory(configuration(), new LispEval(), new JschemeEval());
+    }
+
+    @Override
+    protected List<String> storyPaths() {
+        return new StoryFinder().findPaths(codeLocationFromClass(this.getClass()), "**/*.story", "**/excluded*.story");
+    }
+    
+    @Override
+    @Test
+    public void run() throws Throwable {
+    	super.run();
+    }
+}

+ 64 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/JschemeEval.java

@@ -0,0 +1,64 @@
+package migl.bdd;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+import org.jbehave.core.annotations.Given;
+import org.jbehave.core.annotations.Then;
+import org.jbehave.core.annotations.When;
+
+import jscheme.JScheme;
+import migl.lisp.Lisp;
+import migl.lisp.LispFactory;
+
+public class JschemeEval {
+
+    private JScheme js;
+    private Lisp lisp;
+
+    private Object eval;
+    private Throwable ex;
+    private Object expected;
+
+    @Given("jscheme and a lisp interpreter")
+    public void newInterpreter() {
+        lisp = LispFactory.makeIntepreter();
+        js = new JScheme();
+    }
+
+    @When("the expression evaluated is $expression")
+    public void eval(String expression) {
+        try {
+            ex = null;
+            eval = null;
+            expected = null;
+            eval = lisp.eval(expression);
+            expected = js.eval(expression);
+        } catch (Throwable e) {
+            ex = e;
+        }
+    }
+
+    @Then("the results should be identical")
+    public void checkResultsAreIdentifcal() {
+        assertThat("No own eval?", eval, is(notNullValue()));
+        assertThat("No jscheme eval?", expected, is(notNullValue()));
+        assertThat(eval.toString(), is(equalTo(expected.toString())));
+    }
+
+    @Then("the results should be different")
+    public void checkResultsAreDifferent() {
+        assertThat("No own eval?", eval, is(notNullValue()));
+        assertThat("No jscheme eval?", expected, is(notNullValue()));
+        assertThat(eval.toString(), is(not(equalTo(expected.toString()))));
+    }
+
+    @Then("the error message should be identical")
+    public void checkError() {
+        assertThat("No exception launched?", ex, is(notNullValue()));
+        assertThat(ex.getMessage(), is(equalTo(expected.toString())));
+    }
+}

+ 50 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/LispEval.java

@@ -0,0 +1,50 @@
+package migl.bdd;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+import org.jbehave.core.annotations.Given;
+import org.jbehave.core.annotations.Then;
+import org.jbehave.core.annotations.When;
+
+import migl.lisp.Lisp;
+import migl.lisp.LispError;
+import migl.lisp.LispFactory;
+
+public class LispEval {
+
+    private Lisp lisp;
+
+    private Object eval;
+    private LispError ex;
+
+    @Given("a lisp interpreter")
+    public void newInterpreter() {
+        lisp = LispFactory.makeIntepreter();
+    }
+
+    @When("the expression entered is $expression")
+    public void eval(String expression) {
+        try {
+            eval = lisp.eval(expression);
+            ex = null;
+        } catch (LispError e) {
+            ex = e;
+        }
+    }
+
+    @Then("the result should be $expectedValue")
+    public void checkValue(String expectedValue) {
+        assertThat("An exception launched?", ex, is(nullValue()));
+        assertThat(eval.toString(), equalTo(expectedValue));
+    }
+
+    @Then("the result should display the error message $message")
+    public void checkError(String message) {
+        assertThat("No exception launched?", ex, is(notNullValue()));
+        assertThat(ex.getMessage(), equalTo(message));
+    }
+}

+ 132 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/basic_lisp_operators.story

@@ -0,0 +1,132 @@
+Some additional lisp operations
+
+Narrative:
+Our lisp interpreter should be able to 
+perform those lisp operations. 
+
+Scenario: built-in lisp operators
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+
+|(quote (+ 1 2))|(+ 1 2)|
+|(if #t 3 4)|3|
+|(if #f 3 4)|4|
+|(if (> 10 20) (+ 1 1) (+ 3 3))|6|
+|(if (> 1 2) 3 5)|5|
+|(cons 1 2)|(1 . 2)|
+|(cons 1 ())|(1)|
+|(cons () 1)|(() . 1)|
+|(cons () ())|(())|
+|(cons (cons 1 2)  3)|((1 . 2) . 3)|
+|(cons 1 (cons 2 ())) |(1 2)|
+|(and #f (+ 2 3))|#f|
+|(or #t (+ 2 3))|#t|
+
+Scenario: additional tests from V. Valembois
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+
+|(= 2 2 2)|#t|
+|(= 2)|#t|
+|(< 1)|#t|
+|(> 1)|#t|
+|(< 1 2 3)|#t|
+|(> 1 2 3)|#f|
+|(or)|#f|
+|(or #t)|#t|
+|(or #f)|#f|
+|(or #f #f #t)|#t|
+|(or #f #f #f #f)|#f|
+|(and)|#t|
+|(and #t)|#t|
+|(and #f)|#f|
+|(and #t #t #f)|#f|
+|(and #t #t #t #t)|#t|
+|(and #t #t #t #f)|#f|
+
+Scenario: additional tests from M. Miceli
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+|(= 2.0 2.0)|#t|
+|(= 2.0 3.0)|#f|
+|(<= 3.0 2.0)|#f|
+|(<= 2.0 3.0)|#t|
+|(<= 3.0 2)|#f|
+|(<= 2 3.0)|#t|
+|(>= 3.0 2.0)|#t|
+|(>= 2.0 3.0)|#f|
+|(>= 3 2.0)|#t|
+|(>= 2.0 3)|#f|
+
+
+Scenario: additional tests from A. Franco
+
+ Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+|(< 1 2 1.5)|#f|
+|(= 1 1 1 3)|#f|
+|(> 2 1 1.5)|#f|
+
+Scenario: basic error messages
+
+Given a lisp interpreter
+When the expression entered is <expression>
+Then the result should display the error message <result>
+
+Examples:
+
+|expression  |result|
+|(cons 1)|Invalid number of operands|
+|(cons)|Invalid number of operands|
+|(quote)|Invalid number of operands|
+|(quote (+ 1 2) (+ 1 2))|Invalid number of operands|
+|(+ - 2)|Not a number|
+|(- 2 3 4)|Invalid number of operands|
+|(/)|Invalid number of operands|
+|(/ 2)|Invalid number of operands|
+|(/ 2 4 6)|Invalid number of operands|
+|(if #t 3)|Invalid number of operands|
+|(if #t 3 4 5)|Invalid number of operands|
+|(if (+ 1 2) 3 4)|Not a Boolean|
+|(not (+ 2 3))|Not a Boolean|
+|(and (+ 2 3) #t)|Not a Boolean|
+|(and #t (+ 2 3))|Not a Boolean|
+|(or (+ 2 3) #f)|Not a Boolean|
+|(or #f (+ 2 3))|Not a Boolean|
+|(<)|Invalid number of operands|
+|(>)|Invalid number of operands|
+|(not)|Invalid number of operands|
+|(not #t #t)|Invalid number of operands|
+
+Scenario: Division by zero
+
+Given a lisp interpreter
+When the expression entered is (/ 3 0)
+Then the result should display the error message Division by zero

+ 84 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/basic_operators.story

@@ -0,0 +1,84 @@
+Some additional mathematical operations
+
+Narrative:
+Our lisp interpreter should be able to 
+perform those maths operations. 
+
+Scenario: built-in operators
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+|(not #f)   |#t|
+|(not #t)   |#f|
+|(and #t #t)|#t|
+|(and #t #f)|#f|
+|(and #f #t)|#f|
+|(and #f #f)|#f|
+|(or #t #t) |#t|
+|(or #t #f) |#t|
+|(or #f #t) |#t|
+|(or #f #f) |#f|
+|(> 2 3)|#f|
+|(> 2 2)|#f|
+|(> 2.0 3)|#f|
+|(> 2 3.0)|#f|
+|(> 2.0 3.0)|#f|
+|(> 4 2.0)|#t|
+|(> 4.0 2.0)|#t|
+|(> 5 4)|#t|
+|(>= 2 3)|#f|
+|(>= 2 2)|#t|
+|(< 2 3)|#t|
+|(< 2 2)|#f|
+|(< 2 3.0)|#t|
+|(< 2.0 2)|#f|
+|(< 2.0 2.0)|#f|
+|(<= 2 3)|#t|
+|(<= 2 2)|#t|
+|(<= 3 2)|#f|
+|(= 2 3)|#f|
+|(= 2 2)|#t|
+|(= 2 2.0)|#t|
+|(= 2.0 2)|#t|
+|(= 3.0 2)|#f|
+|(= 2 3.0)|#f|
+|(+ 1 2)|3|
+|(+ 1.0 2)|3.0|
+|(+ 1 2.0)|3.0|
+|(+ 1.0 2.0)|3.0|
+|(+)|0|
+|(+ 1)|1|
+|(+ 1 2)|3|
+|(+ 1 2 3)|6|
+|(+ 1.0)|1.0|
+|(+ 1.0 2.0)|3.0|
+|(+ 1.0 2.0 3.0)|6.0|
+|(*)|1|
+|(* 2)|2|
+|(* 1 2)|2|
+|(* 1 2 3)|6|
+|(* 1.0)|1.0|
+|(* 1.0 2.0)|2.0|
+|(* 1.0 2.0 3.0)|6.0|
+|(* 1.25 2.789 5.5678)|19.41074275|
+|(- 1)|-1|
+|(- 1 2)|-1|
+|(- 3 7)|-4|
+|(- 7 3)|4|
+|(- 1.0)|-1.0|
+|(- 1.0 3.0)|-2.0|
+|(- 2.0 8.0)|-6.0|
+|(- 8.0 2.0)|6.0|
+|(/ 4 2)|2|
+|(/ 5 2)|2|
+|(/ 2 5)|0|
+|(/ 4 2.0)|2.0|
+|(/ 5 2.0)|2.5|
+|(/ 2 5.0)|0.4|
+|(/ 2.0 5.0)|0.4|

+ 118 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-bonus-math_operators.story

@@ -0,0 +1,118 @@
+Some basic mathematical operations
+
+Narrative:
+Our lisp interpreter should be able to 
+perform basic maths. It will rely on the
+methods found in java.lang.Math for functions
+like cos, sin, abs, etc.
+
+Scenario: built-in operators
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+|(+ 1 1)     |  2   |
+|(+ 1 2 3 4) | 10   |
+|(- 5)       | -5   |
+|(- 1 3)     | -2   |
+|(* 1 3)     |  3   |
+|(* 1 3 5 7) |105   |
+|(/ 3 2)     |  1   |
+|(max 2 3)   |  3   |
+
+Scenario: Division by zero
+
+Given a lisp interpreter
+When the expression entered is (/ 3 0)
+Then the result should display the error message Division by zero
+
+Scenario: operands must be evaluated
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+|(+ (* 2 3) (- 8 5))  |  9   |
+|(* (+ 1 (* 2 3) 4) 9) | 99   |
+|(- (* 2 3) (* 3 4))| -6|
+|(/ (* 2 7) (* 4 5.0))|0.7|
+|(if (or (> 4 5) (< 4 5)) (+ 2 3) (- 3 2))| 5   |
+|(or (= (+ 2 3) 5 (/ 10 2)) (> 5 0))|#t|
+|(and (> (+ 2 3) (- 9 8)) (= (* 3 3) (+ 3 6) (/ 27 3) (- 12 3)))|#t|
+|(not (> 26 56))|#t|
+
+Scenario: java.lang.Math functions
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression|result|
+|(abs (- 8))  |8 |
+|(abs (- 8.0))|8.0 |
+|(cbrt 8.0)|2.0|
+|(ceil 8.45)|9.0|
+|(floor 8.45)|8.0|
+|(log10 100)|2.0|
+|(cos 0)   |1.0   |
+|(pow 2 3) |8.0   |
+|(min 2 3) |2     |
+|(min 2.0 3.0)|2.0|
+|(max 2 3) |3     |
+|(max 2.0 3.0)|3.0|
+|(rint 8.45)|8.0|
+|(rint 8.55)|9.0|
+|(round 8.45)|8|
+|(round 8.55)|9|
+|(signum 5.9)|1.0|
+|(signum (- 5.9))|-1.0|
+|(signum 0.0)|0.0|
+
+Scenario: Wrong number of operands for Math methods poke M. Valembois
+
+Given a lisp interpreter
+When the expression entered is <expression>
+Then the result should display the error message Invalid number of operands
+
+Examples:
+
+|expression|
+|(abs 8 9)  |
+|(abs)|
+|(abs 8.0 9.0)|
+|(cbrt 8.0 16.0)|
+|(cbrt)|
+|(ceil 8.45 9.1)|
+|(ceil)|
+|(floor 8.45 9.12)|
+|(floor)|
+|(log10 100 1000)|
+|(log10)|
+|(cos 0 90)|
+|(cos)|
+|(pow 2 3 4)|
+|(pow)|
+|(min 2 3 4) |
+|(min)|
+|(min 2.0 3.0 4.0)|
+|(max 2 3 4) |
+|(max)|
+|(max 2.0 3.0 4.0)|
+|(rint 8.45 9.45)|
+|(rint)|
+|(round 8.45 9.55)|
+|(round)|
+|(signum 5.9 (- 7.8))|
+|(signum)|

+ 42 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-magniez.story

@@ -0,0 +1,42 @@
+Some basic mathematical operations
+
+Narrative:
+Examples contributed by Alexandre Magniez to improve tests code coverage.
+
+Scenario: built-in operators
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+|(max 1.2 2.2)|	 2.2|
+|(min 1.2 2.2)|	1.2|
+|(+ 1.0 2.0) |	3.0|
+|(- 2.0 1.0)|	1.0|
+|(* 2.0 1.0)| 	2.0|
+|(/ 2.0 1.0)| 	2.0|
+|(< 1 2)	|    #t|
+|(< 1.2 2.2)|    #t|
+|(> 1 2)	|	 #f|
+|(> 1.2 2.2)|	 #f|
+|(abs -5.0)	|	5.0|
+|(pow 1.0 2.0)|	1.0|
+
+
+
+Scenario: basic error messages
+
+Given a lisp interpreter
+When the expression entered is <expression>
+Then the result should display the error message <result>
+
+Examples:
+
+|expression  |result|
+|(/ 1 2 3)|Invalid number of operands|
+|(abs 1 2)|Invalid number of operands|
+|(pow 1 2 3)|Invalid number of operands|

+ 23 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-sem8-list_manipulation.story

@@ -0,0 +1,23 @@
+Some list related operations
+
+Narrative:
+Most of the features of the interpreter rely
+on the use of cons and lists. As such, it is important
+to test thoroughly those features.
+
+Scenario: cons operator
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression|result|
+|(cons 1 2)   |(1 . 2)     |
+|(cons 1 nil) |(1)   |
+|(cons nil 1) |(() . 1)     |
+|(cons nil nil)   |(())     |
+|(cons (cons 1 2)  3) |((1 . 2) . 3)   |
+|(cons 1 (cons 2 nil)) |(1 2)   |

+ 184 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-sem8-simplecontext.story

@@ -0,0 +1,184 @@
+Some simple context-aware operations
+
+Description:
+
+As in any language, lisp interpreters allow to
+store information in "variables".
+
+A variable is an identifier, which is associated to a lisp
+expression using the operator "define". 
+
+To update the value associated with a variable,
+a specific "set!" operator must be used.
+
+The scope of those variables is by default global, i.e. 
+they can be accessed in any lisp expression after being 
+defined.
+
+A specific case is the one of function (lambda expression) parameters.
+Those variables are not defined explicitly.
+Their scope is limited to the body of the lambda expression.
+
+Narrative:
+
+In order to reuse information, 
+as a casual lisp user
+I want to associate expressions to identifiers using the keyword define.
+
+Scenario: simple definitions
+
+Given a lisp interpreter
+
+When the expression entered is (define a 5)
+Then the result should be 5
+
+When the expression entered is (define b 10)
+Then the result should be 10
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+|(+ a b)       | 15   |
+|(- a b)     | -5   |
+|(* a b)     |  50   |
+|(* 1 a 2 b) | 100   |
+|(/ b a)     |  2   |
+|(max a b)   |  10   |
+|(min a b)   |  5   |
+|(cons a (cons b ()))| (5 10) |
+
+Scenario: overriding definitions
+
+Given a lisp interpreter
+
+When the expression entered is (define a 5)
+Then the result should be 5
+
+When the expression entered is (define b 10)
+Then the result should be 10
+
+When the expression entered is (+ a b)
+Then the result should be 15
+
+When the expression entered is (define b 30)
+Then the result should be 30
+
+When the expression entered is (+ a b)
+Then the result should be 35
+
+When the expression entered is (define a 20)
+Then the result should be 20
+
+When the expression entered is (+ a b)
+Then the result should be 50
+
+Scenario: some students are picky about testing
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should display the error message <result>
+
+Examples:
+
+|expression|result|
+|(define 12 20)|12 is not a valid identifier|
+|(define + 20)|+ is not a valid identifier|
+|(define - 20)|- is not a valid identifier|
+|(define * 20)|* is not a valid identifier|
+|(define / 20)|/ is not a valid identifier|
+|(define or 20)|or is not a valid identifier|
+|(define not 20)|not is not a valid identifier|
+|(define and 20)|and is not a valid identifier|
+|(define lambda 20)|lambda is not a valid identifier|
+|(define define 20)|define is not a valid identifier|
+|(define set! 20)|set! is not a valid identifier|
+|(define cons 20)|cons is not a valid identifier|
+
+
+
+Scenario: modifying the value of an identifier using set!
+
+Given a lisp interpreter
+When the expression entered is (define a 50)
+Then the result should be 50
+
+When the expression entered is (set! a 30)
+Then the result should be 30
+
+When the expression entered is (set! b 20)
+Then the result should display the error message b is undefined
+
+Scenario: defining a function (a lambda expression) with one parameter
+
+Given a lisp interpreter
+
+When the expression entered is (define surprise (lambda (x) (* x x)))
+Then the result should be lambda (x) (* x x)
+
+When the expression entered is (surprise 10)
+Then the result should be 100
+
+Scenario: defining a function (a lambda expression) with two parameters
+
+Given a lisp interpreter
+
+When the expression entered is (define surprise (lambda (x y) (* x y)))
+Then the result should be lambda (x y) (* x y)
+
+When the expression entered is (surprise 10 20)
+Then the result should be 200
+
+Scenario: a function has its own context
+
+Given a lisp interpreter
+
+When the expression entered is (define x 10)
+Then the result should be 10
+
+When the expression entered is x
+Then the result should be 10
+
+When the expression entered is (define surprise (lambda (x) (* x x)))
+Then the result should be lambda (x) (* x x)
+
+When the expression entered is (surprise 15)
+Then the result should be 225
+
+When the expression entered is x
+Then the result should be 10
+
+
+Scenario: identifier is not defined
+
+Given a lisp interpreter
+
+When the expression entered is x
+Then the result should display the error message x is undefined
+
+When the expression entered is (surprise 15)
+Then the result should display the error message surprise is undefined
+
+
+Scenario: first group inspiration
+
+Given a lisp interpreter
+
+When the expression entered is (define n 10)
+Then the result should be 10
+
+When the expression entered is (define f (lambda (x) (* n x)))
+Then the result should be lambda (x) (* n x)
+
+When the expression entered is (f 4)
+Then the result should be 40
+
+When the expression entered is (set! n 100)
+Then the result should be 100
+
+When the expression entered is (f 4)
+Then the result should be 400
+

+ 116 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-sem9-advancedcontext.story

@@ -0,0 +1,116 @@
+The final touch to our interpreter
+
+Narrative:
+
+In order to have a fully working interpreter, 
+
+as a casual lisp user
+
+I want to better manipulate lists, and express functions (lambda).
+
+Scenario: cons and list operations
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+|(cons 1 2)  | (1 . 2)|
+|(car (cons 1 2))| 1  |
+|(cdr (cons 1 2))| 2  |
+|(cons 1 (cons 2 ())) | (1 2)   |
+|(car (cons 1 (cons 2 ()))) | 1 |
+|(cdr (cons 1 (cons 2 ()))) | (2) |
+|(list 1 2 3)   |  (1 2 3)   |
+
+Scenario: more complex functions (lambdas)
+
+Given a lisp interpreter
+
+When the expression entered is (define twice (lambda (x) (* 2 x)))
+Then the result should be lambda (x) (* 2 x)
+
+When the expression entered is (define strange (lambda (f x) (f (f x))))
+Then the result should be lambda (f x) (f (f x))
+
+When the expression entered is (strange twice 10)
+Then the result should be 40
+
+Scenario: recursive functions - factorial
+
+Given a lisp interpreter
+
+When the expression entered is (define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))
+Then the result should be lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))
+
+When the expression entered is (fact 0)
+Then the result should be 1
+
+When the expression entered is (fact 1)
+Then the result should be 1
+
+When the expression entered is (fact 2)
+Then the result should be 2
+
+When the expression entered is (fact 3)
+Then the result should be 6
+
+When the expression entered is (fact 10)
+Then the result should be 3628800
+
+When the expression entered is (fact 100)
+Then the result should be 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
+
+Scenario: recursive functions - fibonacci
+
+Given a lisp interpreter
+
+When the expression entered is (define fib (lambda (n) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2))))))
+Then the result should be lambda (n) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2))))
+
+When the expression entered is (define range (lambda (a b) (if (= a b) (list) (cons a (range (+ a 1) b)))))
+Then the result should be lambda (a b) (if (= a b) (list) (cons a (range (+ a 1) b)))
+
+When the expression entered is (range 0 10)
+Then the result should be (0 1 2 3 4 5 6 7 8 9)
+
+When the expression entered is (map fib (range 0 10))
+Then the result should be (1 1 2 3 5 8 13 21 34 55)
+
+When the expression entered is (map fib (range 0 20))
+Then the result should be (1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765)
+
+Scenario: back to LCPF
+
+Given a lisp interpreter
+
+When the expression entered is (define f (lambda (x) (lambda (y) (* x y))))
+Then the result should be lambda (x) (lambda (y) (* x y))
+
+When the expression entered is ((f 10) 20)
+Then the result should be 200
+
+Scenario: some potential error
+
+Given a lisp interpreter
+
+When the expression entered is (define f (lambda (+ 2 3)))
+Then the result should display the error message Invalid number of operands
+
+Scenario: some students are picky about testing
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should display the error message <result>
+
+Examples:
+
+|expression|result|
+|(define car 20)|car is not a valid identifier|
+|(define cdr 20)|cdr is not a valid identifier|
+|(define list 20)|list is not a valid identifier|
+

+ 44 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/excluded-sem9-jscheme_behavior.story

@@ -0,0 +1,44 @@
+Some basic mathematical operations
+
+Narrative:
+We need to check that our interpreter performs the
+same operations as jscheme (at least on classical
+lisp/scheme operations). It may differ on some 
+specific but documented cases.
+
+Scenario: built-in operators
+
+Given jscheme and a lisp interpreter
+
+When the expression evaluated is <expression>
+Then the results should be identical
+
+Examples:
+
+|expression|
+|(+ 1 1)   |
+|(+ 1 1 1) |
+|(+ 1 1 1 2) |
+|(- 1 3)   |
+|(* 1 3)   |
+|(* 1 3 5) |
+|(* 1 3 5 7) |
+|(/ 3 2)   |
+|(max 2 3) |
+
+Scenario: cons
+
+Given jscheme and a lisp interpreter
+
+When the expression evaluated is <expression>
+Then the results should be identical
+
+Examples:
+
+|expression|
+|(cons 1 2)   |
+|(cons 1 ()) |
+|(cons () 1) |
+|(cons () ())   |
+|(cons (cons 1 2)  3) |
+|(cons 1 (cons 2 ())) |

+ 22 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/bdd/more_operator_tests.story

@@ -0,0 +1,22 @@
+Some additional mathematical operations
+
+Narrative:
+Our lisp interpreter should be able to 
+perform those maths operations. 
+
+Scenario: built-in operators
+
+Given a lisp interpreter
+
+When the expression entered is <expression>
+Then the result should be <result>
+
+Examples:
+
+|expression  |result|
+|(- (+ 2 3)) | -5 |
+|(- 9 20) | -11 |
+|(- (+ (* 2 3) (/ 9 3)) 20) | -11 |
+|(- 9 (* 4 5)) | -11 |
+|(- (* 4 5) 9) | 11 |
+|(- (+ (* 2 3) (/ 9 3)) (* 4 5)) | -11 |

+ 13 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/lisp/AbstractTDD.java

@@ -0,0 +1,13 @@
+package migl.lisp;
+
+import org.junit.Before;
+
+public abstract class AbstractTDD {
+
+    protected Lisp lisp;
+
+    @Before
+    public void init() {
+        lisp = LispFactory.makeIntepreter();
+    }
+}

+ 109 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/lisp/LispParserTest.java

@@ -0,0 +1,109 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertEquals;
+
+import java.math.BigInteger;
+
+import org.junit.Test;
+
+import migl.util.ConsList;
+import migl.util.ConsListFactory;
+
+/**
+ * The aim of those tests is to check that a basic lisp String can be translated
+ * into a list of Java objects.
+ * 
+ * The main issue here is to be able to return the proper Java type for each
+ * object. Note that Lisp using arbitrary precision arithmetic, it is important
+ * to use the BigInteger and Double classes to represent numbers.
+ * 
+ * Note that all inputs are valid for now. Invalid inputs will be tested in
+ * future test cases.
+ * 
+ * @author leberre
+ *
+ */
+public class LispParserTest extends AbstractTDD {
+
+    @Test
+    public void testParsingSingleElement() throws LispError {
+        assertEquals("r", lisp.parse("r"));
+        assertEquals(BigInteger.valueOf(18), lisp.parse("18"));
+        assertEquals(Double.valueOf("-3.14E12"), lisp.parse("-3.14E12"));
+    }
+
+    @Test
+    public void testParsingSingleElementInList() throws LispError {
+        ConsList<Object> expected = ConsListFactory.nil().prepend("r");
+        assertEquals(expected, lisp.parse("(r)"));
+        expected = ConsListFactory.nil().prepend(BigInteger.valueOf(18));
+        assertEquals(expected, lisp.parse("(18)"));
+        expected = ConsListFactory.nil().prepend(Double.valueOf("-3.14E12"));
+        assertEquals(expected, lisp.parse("(-3.14E12)"));
+    }
+
+    @Test
+    public void testParsingSingleExpression() throws LispError {
+        ConsList<Object> expected = ConsListFactory.nil().prepend("r").prepend("r").prepend("+");
+        assertEquals(expected, lisp.parse("(+ r r)"));
+        expected = ConsListFactory.nil().prepend(BigInteger.valueOf(2)).prepend("x").prepend(">");
+        assertEquals(expected, lisp.parse("(> x 2)"));
+        expected = ConsListFactory.nil().prepend(BigInteger.valueOf(10)).prepend("z").prepend("define");
+        assertEquals(expected, lisp.parse("(define z 10)"));
+    }
+
+    @Test
+    public void testParsingSimpleImbricatedExpressions() throws LispError {
+        ConsList<Object> l1 = ConsListFactory.nil().prepend("r").prepend("r").prepend("+");
+        ConsList<Object> expected = ConsListFactory.nil().prepend(BigInteger.valueOf(10)).prepend(l1).prepend("*");
+        assertEquals(expected, lisp.parse("(* (+ r r) 10)"));
+        l1 = ConsListFactory.nil().prepend(BigInteger.valueOf(2)).prepend(BigInteger.valueOf(1)).prepend("+");
+        expected = ConsListFactory.nil().prepend(l1).prepend("quote");
+        assertEquals(expected, lisp.parse("(quote (+ 1 2))"));
+    }
+
+    @Test
+    public void testParsingOtherLispKeyworkds() throws LispError {
+        ConsList<Object> l1 = ConsListFactory.nil().prepend(BigInteger.valueOf(2)).prepend(BigInteger.valueOf(1))
+                .prepend(">");
+        ConsList<Object> expected = ConsListFactory.nil().prepend(BigInteger.valueOf(5)).prepend(BigInteger.valueOf(3))
+                .prepend(l1).prepend("if");
+        assertEquals(expected, lisp.parse("(if (> 1 2) 3 5)"));
+        expected = ConsListFactory.nil().prepend(BigInteger.valueOf(15)).prepend("bb8").prepend("define");
+        assertEquals(expected, lisp.parse("(define bb8 15)"));
+    }
+
+    @Test
+    public void testTypeOfTheObjectsInTheList() throws LispError {
+        @SuppressWarnings("unchecked")
+        ConsList<Object> objects = (ConsList<Object>) lisp.parse("(+ 1 2.0)");
+        assertEquals(3, objects.size());
+        assertEquals(String.class, objects.car().getClass());
+        assertEquals(BigInteger.class, objects.cdr().car().getClass());
+        assertEquals(Double.class, objects.cdr().cdr().car().getClass());
+    }
+
+    @Test
+    public void testTypeOfBooleanConstants() throws LispError {
+        @SuppressWarnings("unchecked")
+        ConsList<Object> objects = (ConsList<Object>) lisp.parse("(or #t #f)");
+        assertEquals(3, objects.size());
+        assertEquals(String.class, objects.car().getClass());
+        assertEquals(LispBoolean.class, objects.cdr().car().getClass());
+        assertEquals(LispBoolean.TRUE, objects.cdr().car());
+        assertEquals(LispBoolean.class, objects.cdr().cdr().car().getClass());
+        assertEquals(LispBoolean.FALSE, objects.cdr().cdr().car());
+    }
+    
+    @Test
+    public void testParsingSingleExpressionMHachinLikesSpaces() throws LispError {
+        ConsList<Object> expected = ConsListFactory.nil().prepend("r").prepend("r").prepend("+");
+        assertEquals(expected, lisp.parse("(+ r   r)"));
+        expected = ConsListFactory.nil().prepend(BigInteger.valueOf(2)).prepend("x").prepend(">");
+        assertEquals(expected, lisp.parse("(> x 2) "));
+        expected = ConsListFactory.nil().prepend(BigInteger.valueOf(10)).prepend("z").prepend("define");
+        assertEquals(expected, lisp.parse(" (define z 10)"));
+        assertEquals(expected, lisp.parse(" (define z 10) "));
+        assertEquals(expected, lisp.parse(" (  define   z     10  )  "));
+    }
+}

+ 118 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/lisp/MoreLispParserTest.java

@@ -0,0 +1,118 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertEquals;
+
+import java.math.BigInteger;
+
+import org.junit.Test;
+
+import migl.util.ConsList;
+import migl.util.ConsListFactory;
+
+/**
+ * Those tests represent incorrect input for our lisp interpreter.
+ * 
+ * @author leberre
+ *
+ */
+public class MoreLispParserTest extends AbstractTDD {
+
+    @Test(expected = LispError.class)
+    public void testNoEndingParenthesis() throws LispError {
+        lisp.parse("(r");
+    }
+
+    @Test(expected = LispError.class)
+    public void testNoOpeningingParenthesis() throws LispError {
+        lisp.parse("r)");
+    }
+
+    @Test(expected = LispError.class)
+    public void testMissingEndOfList() throws LispError {
+        lisp.parse("(< (+ 1 3) 4");
+    }
+
+    @Test(expected = LispError.class)
+    public void testAlternativeMissingEndOfList() throws LispError {
+        lisp.parse("(< (+ 1 3 4)");
+    }
+
+    @Test(expected = LispError.class)
+    public void testMissingBeginningOfList() throws LispError {
+        lisp.parse("< (+ 1 3 4))");
+    }
+
+    @Test(expected = LispError.class)
+    public void testAlternativeMissingBeginningOfList() throws LispError {
+        lisp.parse("(< + 1 3 4))");
+    }
+
+    @Test(expected = LispError.class)
+    public void testCountingIsNotEnoughAkaTestDessaint() throws LispError {
+        lisp.parse(")< + 1 3 4(");
+    }
+
+    @Test(expected = LispError.class)
+    public void testAlternativeCountingIsNotEnoughAkaTestDessaint() throws LispError {
+        lisp.parse("(< )+ 1 3 4()");
+    }
+
+    @Test
+    public void testSpacesInExpressionShouldNotMatterAkaDessaintAgain() throws LispError {
+        ConsList<Object> l1 = ConsListFactory.nil().prepend("r").prepend("r").prepend("+");
+        ConsList<Object> expected = ConsListFactory.nil().prepend(BigInteger.valueOf(10)).prepend(l1).prepend("*");
+        assertEquals(expected, lisp.parse("(*  (+ r r) 10)"));
+        assertEquals(expected, lisp.parse("(* ( + r r ) 10)"));
+        assertEquals(expected, lisp.parse("(* (+ r r) 10 ) "));
+        assertEquals(expected, lisp.parse(" (* (+ r r) 10) "));
+        assertEquals(expected, lisp.parse(" ( * ( + r r ) 10 ) "));
+    }
+
+    @Test
+    public void testTabsInExpressionShouldNotMatterAkaTestVrand() throws LispError {
+        ConsList<Object> l1 = ConsListFactory.nil().prepend("r").prepend("r").prepend("+");
+        ConsList<Object> expected = ConsListFactory.nil().prepend(BigInteger.valueOf(10)).prepend(l1).prepend("*");
+        assertEquals(expected, lisp.parse("(*\t(+\tr\tr)\t10)"));
+        assertEquals(expected, lisp.parse("(*\t\t(\t+\tr\tr\t)\t10)"));
+        assertEquals(expected, lisp.parse("(*\t(+\tr\tr)\t10\t)\t"));
+        assertEquals(expected, lisp.parse("\t(*\t(+\tr\tr)\t10)\t"));
+        assertEquals(expected, lisp.parse("\t(\t* (\t+\tr\tr\t)\t10\t)\t"));
+    }
+
+    @Test(expected = LispError.class)
+    public void testThatEmptyStringCannotBeEvaluatedAkaVrandIsBack() throws LispError {
+        lisp.parse("");
+    }
+
+    @Test(expected = LispError.class)
+    public void testThatOnlySpacesCannotBeEvaluatedAkaVrandIsBack() throws LispError {
+        lisp.parse("   ");
+    }
+
+    @Test(expected = LispError.class)
+    public void testThatOnlyTabsCannotBeEvaluatedAkaVrandIsBack() throws LispError {
+        lisp.parse("\t\t");
+    }
+
+    @Test(expected = LispError.class)
+    public void testThatTwoElementsIsNotCorrect() throws LispError {
+        lisp.parse("foo bar");
+    }
+
+    @Test(expected = LispError.class)
+    public void testThatRemainingDataCannotBeIgnored() throws LispError {
+        lisp.parse("(* x y) foo");
+    }
+
+    @Test(expected = LispError.class)
+    public void testThatRemainingDataCannotBeIgnoredTwoLists() throws LispError {
+        lisp.parse("(* x y)(- y 20)");
+    }
+
+    @Test
+    public void testParsingSingleExpressionHachinLovesSpaces() throws LispError {
+        assertEquals("r", lisp.parse("r   "));
+        ConsList<Object> expected = ConsListFactory.nil().prepend("+");
+        assertEquals(expected, lisp.parse("(+        ) "));
+    }
+}

+ 34 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/lisp/ReplTest.java

@@ -0,0 +1,34 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ReplTest {
+
+    private ByteArrayOutputStream myout;
+
+    @Before
+    public void setUp() {
+        myout = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(myout));
+    }
+
+    @Test
+    public void test() {
+        String sep = System.lineSeparator();
+        ByteArrayInputStream myin = new ByteArrayInputStream(("(+ 1 2)" + sep + "quit" + sep).getBytes());
+        System.setIn(myin);
+        REPL.main(new String[] {});
+        assertEquals("My super own Lisp/Scheme interpreter 2019" + sep
+                + "Enter a valid Lisp expression followed by Enter. type 'quit' to exit." + sep + "> " + "3" + sep
+                + "> " + "Bye." + sep, myout.toString());
+
+    }
+
+}

+ 108 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/util/ConsListTest.java

@@ -0,0 +1,108 @@
+package migl.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ConsListTest {
+
+	private ConsList<Integer> list;
+
+	@Before
+	public void init() {
+		list = ConsListFactory.nil();
+	}
+
+	@Test
+	public void testListIsEmptyByDefault() {
+		assertTrue(list.isEmpty());
+		assertEquals(0, list.size());
+	}
+
+	@Test
+	public void testPrepend() {
+		assertEquals(0, list.size());
+		list = list.prepend(1);
+		assertEquals(1, list.size());
+		assertEquals(1, list.car().intValue());
+		list = list.prepend(2);
+		assertEquals(2, list.size());
+		assertEquals(2, list.car().intValue());
+		list = list.prepend(3);
+		assertEquals(3, list.size());
+		assertEquals(3, list.car().intValue());
+	}
+
+	@Test
+	public void testPrependSharesSublist() {
+		ConsList<Integer> list2 = list.prepend(2);
+		assertEquals(list, list2.cdr());
+		assertSame(list, list2.cdr());
+		ConsList<Integer> list3 = list2.prepend(1);
+		assertEquals(list2, list3.cdr());
+		assertSame(list2, list3.cdr());
+	}
+
+	@Test
+	public void testAppend() {
+		assertEquals(0, list.size());
+		list = list.append(1);
+		assertEquals(1, list.size());
+		assertEquals(1, list.car().intValue());
+		list = list.append(2);
+		assertEquals(2, list.size());
+		assertEquals(1, list.car().intValue());
+		assertEquals(2, list.cdr().car().intValue());
+		list = list.append(3);
+		assertEquals(3, list.size());
+		assertEquals(1, list.car().intValue());
+		assertEquals(2, list.cdr().car().intValue());
+		assertEquals(3, list.cdr().cdr().car().intValue());
+	}
+
+	@Test
+	public void testAppendDoesNoShareSublist() {
+		ConsList<Integer> list2 = list.append(1);
+		assertEquals(list, list2.cdr());
+		ConsList<Integer> list3 = list2.append(2);
+		assertEquals(list2.car(), list3.car());
+		assertNotSame(list2, list3.cdr());
+	}
+
+	@Test
+	public void testToStringEmpty() {
+		assertEquals("()", list.toString());
+	}
+
+	@Test
+	public void testToStringSingleton() {
+		list = list.prepend(1);
+		assertEquals("(1)", list.toString());
+	}
+
+	@Test
+	public void testToStringTwoElements() {
+		list = list.prepend(2);
+		list = list.prepend(1);
+		assertEquals("(1 2)", list.toString());
+	}
+
+	@Test
+	public void testEqualsToArray() {
+		list = list.prepend(3).prepend(2).prepend(1);
+		Object[] liste = { 1, 2, 3 };
+		assertArrayEquals(liste, list.toArray());
+
+	}
+
+	@Test
+	public void testEqualsReduce() {
+		list = list.prepend(3).prepend(2).prepend(1);
+		assertEquals(6, list.reduce(0, Integer::sum).intValue());
+	}
+}

+ 94 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/util/ConsTest.java

@@ -0,0 +1,94 @@
+package migl.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+public class ConsTest {
+
+    @Test
+    public void testNilCons() {
+        Cons<String, String> c1 = Cons.nil();
+        assertNull(c1.left());
+        assertNull(c1.right());
+        assertEquals("(null . null)", c1.toString());
+    }
+
+    @Test
+    public void testSimpleCons() {
+        Cons<String, String> c1 = new Cons<>("a", "b");
+        assertEquals("(a . b)", c1.toString());
+        assertEquals("a", c1.left());
+        assertEquals("b", c1.right());
+    }
+
+    @Test
+    public void testNestedCons() {
+        Cons<String, Cons<String, String>> c1 = new Cons<>("a", new Cons<>("b", "c"));
+        assertEquals("(a . (b . c))", c1.toString());
+    }
+
+    @Test
+    public void testEquals() {
+        Cons<String, String> c1 = new Cons<>("a", "b");
+        Cons<String, String> c2 = new Cons<>("a", "b");
+        Cons<String, String> c3 = new Cons<>("a", "c");
+        Cons<String, String> c4 = new Cons<>("c", "b");
+        Cons<String, String> c5 = new Cons<>("c", "d");
+        assertEquals(c1, c2);
+        assertNotEquals(c1, null);
+        assertNotEquals(c1, true);
+        assertNotEquals(null, c2);
+        assertNotEquals(true, c2);
+        assertNotEquals(c1, c3);
+        assertNotEquals(c1, c4);
+        assertNotEquals(c1, c5);
+    }
+
+    @Test
+    public void testConsEquals() {
+        Cons<String, String> c1 = new Cons<>("a", "b");
+        Cons<String, String> c2 = new Cons<>("a", null);
+        Cons<String, String> c3 = new Cons<>("a", "c");
+        Cons<String, String> c4 = new Cons<>("a", "a");
+        Cons<String, String> c5 = new Cons<>(null, "a");
+        Cons<String, String> c6 = new Cons<>("a", "c");
+        Cons<String, String> c7 = new Cons<>("a", null);
+
+        assertTrue(c1.equals(c1));
+        assertFalse(c2.equals(c3));
+        assertFalse(c2.equals(new Cons<>("b", null)));
+        assertTrue(c3.equals(c6));
+        assertFalse(c4.equals(c5));
+        assertFalse(c5.equals(c6));
+        assertTrue(c2.equals(c7));
+        assertFalse(c5.equals(new Cons<>(null, "b")));
+        assertEquals(c1.hashCode(), c1.hashCode());
+        assertEquals(c3.hashCode(), c6.hashCode());
+        assertEquals(c2.hashCode(), c7.hashCode());
+    }
+
+    @Test
+    public void testConsHashCode() {
+        Cons<String, String> c1 = new Cons<>("a", "b");
+        Cons<String, String> c2 = new Cons<>("a", null);
+        Cons<String, String> c3 = new Cons<>(null, "a");
+        Cons<String, String> c4 = new Cons<>(null, null);
+        Map<Cons<String, String>, String> map = new HashMap<>();
+        map.put(c1, "C1");
+        map.put(c2, "C2");
+        map.put(c3, "C3");
+        map.put(c4, "C4");
+        assertEquals("C1", map.get(c1));
+        assertEquals("C2", map.get(c2));
+        assertEquals("C3", map.get(c3));
+        assertEquals("C4", map.get(c4));
+    }
+}

+ 156 - 0
TDD2019IMPL/TDD2019TESTS/src/migl/util/MoreConsListTest.java

@@ -0,0 +1,156 @@
+package migl.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class MoreConsListTest {
+
+    private ConsList<Integer> list;
+
+    @Before
+    public void init() {
+        list = ConsListFactory.nil();
+    }
+
+    @Test(timeout = 20000)
+    public void testPrepend() {
+        for (int i = 0; i < 10000; i++) {
+            list = list.prepend(i);
+        }
+        assertEquals(10000, list.size());
+        ConsList<Integer> list2 = list.prepend(666);
+        assertSame(list, list2.cdr());
+    }
+
+    @Test(timeout = 20000)
+    public void testEqualsEfficiency() {
+        for (int i = 0; i <= 10000; i++) {
+            list = list.prepend(i);
+        }
+        ConsList<Integer> list2 = list.prepend(666);
+        assertEquals(list, list2.cdr());
+    }
+
+    @Test
+    public void testIteratorOnEmptyList() {
+        for (Integer i : list) {
+            fail("there should be no element " + i + " in the list!!!");
+        }
+    }
+
+    @Test(expected = NoSuchElementException.class)
+    public void testIteratorNextOnEmptyList() {
+        list.iterator().next();
+    }
+
+    @Test(expected = NoSuchElementException.class)
+    public void testIteratorWithNonEmptyList() {
+        list = list.prepend(4).prepend(3).prepend(2).prepend(1);
+        Iterator<Integer> it = list.iterator();
+        assertTrue(it.hasNext());
+        assertEquals(1, it.next().intValue());
+        assertTrue(it.hasNext());
+        assertEquals(2, it.next().intValue());
+        assertTrue(it.hasNext());
+        assertEquals(3, it.next().intValue());
+        assertTrue(it.hasNext());
+        assertEquals(4, it.next().intValue());
+        assertFalse(it.hasNext());
+        it.next();
+    }
+
+    @Test
+    public void testSingletonFactory() {
+        ConsList<Integer> list2 = ConsListFactory.singleton(5);
+        assertEquals(1, list2.size());
+        assertEquals(5, list2.car().intValue());
+    }
+
+    @Test
+    public void testListFromVarargs() {
+        ConsList<Integer> list2 = ConsListFactory.asList(6, 66, 666);
+        assertEquals(3, list2.size());
+        Iterator<Integer> it = list2.iterator();
+        assertTrue(it.hasNext());
+        assertEquals(6, it.next().intValue());
+        assertTrue(it.hasNext());
+        assertEquals(66, it.next().intValue());
+        assertTrue(it.hasNext());
+        assertEquals(666, it.next().intValue());
+        assertFalse(it.hasNext());
+    }
+
+    @Test
+    public void testMap() {
+        ConsList<Integer> list2 = ConsListFactory.asList(6, 66, 666);
+        ConsList<String> list3 = ConsListFactory.asList("6", "66", "666");
+        assertEquals(list2, list3.map(Integer::valueOf));
+        assertEquals(list3, list2.map((i) -> Integer.toString(i)));
+    }
+
+    @Test
+    public void testAdditionalToString() {
+        list = list.prepend(10).prepend(9).prepend(8);
+        assertEquals("(8 9 10)", list.toString());
+        ConsList<Object> olist = ConsListFactory.nil();
+        olist = olist.prepend("Truc").prepend(list).prepend(45);
+        assertEquals("(45 (8 9 10) Truc)", olist.toString());
+    }
+
+    @Test
+    public void testAllowNullInList() {
+        ConsList<Object> olist = ConsListFactory.nil();
+        olist = olist.prepend("Truc").prepend(null).prepend(45);
+        assertEquals("(45 null Truc)", olist.toString());
+    }
+
+    @Test
+    public void testEqualsWithNull() {
+        assertNotEquals(list, null);
+    }
+
+    @Test
+    public void testEqualsWithDifferentLists() {
+        list = list.prepend(10).prepend(9).prepend(8);
+        ConsList<Integer> list2 = ConsListFactory.nil();
+        list2 = list2.prepend(8).prepend(9).prepend(10);
+        assertNotEquals(list, list2);
+    }
+
+    @Test
+    public void testEqualsWithEqualLists() {
+        list = list.prepend(10).prepend(9).prepend(8);
+        ConsList<Integer> list2 = ConsListFactory.nil();
+        list2 = list2.prepend(10).prepend(9).prepend(8);
+        assertEquals(list, list2);
+    }
+
+    @Test
+    public void testEqualsWithDifferentTypes() {
+        list = list.prepend(10).prepend(9).prepend(8);
+        ConsList<String> list2 = ConsListFactory.nil();
+        list2 = list2.prepend("10").prepend("9").prepend("8");
+        assertNotEquals(list, list2);
+    }
+
+    @Test(expected = NoSuchElementException.class)
+    public void testCarOnEmptyList() {
+        list.car();
+    }
+
+    @Test
+    public void testCdrOnEmptyList() {
+        assertEquals(ConsListFactory.nil(), list.cdr());
+    }
+
+}

+ 148 - 0
TDD2019IMPL/build.xml

@@ -0,0 +1,148 @@
+<project name="tdd" default="tests" basedir="." xmlns:sonar="antlib:org.sonar.ant" xmlns:jacoco="antlib:org.jacoco.ant">
+	<property name="project.java.version" value="1.8" />
+	<property name="encoding" value="UTF-8" />
+	<property name="sonar.login" value="202fbf7d57aa6517e5b81dff5a9a15ae213212ac" />
+	<!-- LE RESTE DOIT ETRE BON -->
+	<property name="build" value="build" />
+	<property name="testreports" value="testreports" />
+	<property name="src" value="src" />
+	<!--property name="etudiant" value="arthur_brandao" /-->
+
+	<!-- Define the SonarQube global properties (the most usual way is to pass these properties via the command line) -->
+	<property name="sonar.host.url" value="https://forge.univ-artois.fr/sonar67" />
+	<property name="sonar.projectKey" value="${etudiant}:2019:MyLisp" />
+	<property name="sonar.projectName" value="${etudiant} Lisp 19" />
+	<property name="sonar.projectVersion" value="1.0" />
+	<property name="sonar.java.source" value="${project.java.version}" />
+	<property name="sonar.java.binaries" value="build" />
+	<property name="sonar.java.libraries" value="lib/*.jar" />
+	<property name="sonar.sources" value="src" />
+	<property name="sonar.exclusions" value="**/*Test*" />
+	<property name="sonar.tests" value="TDD2019TESTS/src,TDD2019OWNTESTS/src" />
+	<property name="sonar.junit.reportPaths" value="${testreports}" />
+	<property name="sonar.jacoco.reportPaths" value="${testreports}/jacoco.exec" />
+    <property name="sonar.pitest.reportsDirectory" value="${testreports}" />
+	<property name="sonar.web.javaAdditionalOpts" value="-Dhttps.proxyHost=cache-etu.univ-artois.fr -Dhttps.proxyPort=3128" />
+	<target name="prepare" description="Cree les repertoires et initialise certaines valeurs">
+		<!-- Create the time stamp -->
+		<tstamp />
+		<mkdir dir="${build}" />
+		<mkdir dir="${testreports}" />
+	</target>
+
+	<path id="mypath">
+		<pathelement location="${build}" />
+		<fileset dir="lib">
+			<include name="*.jar" />
+		</fileset>
+	</path>
+
+	<target name="build" description="Compile les fichiers Java" depends="prepare">
+		<javac includeantruntime="true" srcdir="${src}" destdir="${build}" source="${project.java.version}" debug="true" encoding="${encoding}">
+			<classpath refid="mypath" />
+		</javac>
+	</target>
+
+	<target name="clean" description="Efface tous les fichiers generes">
+		<!-- Delete directory trees -->
+		<delete dir="${build}" />
+		<delete dir="${testreports}" />
+		<delete dir="${target}" />
+	</target>
+
+	<target name="compilepublictests">
+		<echo>Compilation des tests publics</echo>
+		<javac includeantruntime="true" srcdir="TDD2019TESTS/src" destdir="${build}" source="${project.java.version}" debug="true" encoding="${encoding}">
+			<classpath refid="mypath" />
+		</javac>
+		<copy todir="${build}">
+			<fileset dir="TDD2019TESTS/src">
+				<include name="**/*.story" />
+			</fileset>
+		</copy>
+	</target>
+	<target name="compileprivatetests" if="private.tests.found">
+		<echo>Compilation des tests privés</echo>
+		<javac includeantruntime="true" srcdir="TDD2019HIDDENTESTS/src" destdir="${build}" source="${project.java.version}" debug="true" encoding="${encoding}">
+			<classpath refid="mypath" />
+		</javac>
+
+		<copy todir="${build}">
+			<fileset dir="TDD2019HIDDENTESTS/src">
+				<include name="**/*.story" />
+			</fileset>
+		</copy>
+	</target>
+	<target name="compileowntests">
+		<echo>Compilation des tests personnels</echo>
+		<javac includeantruntime="true" srcdir="TDD2019OWNTESTS/src" destdir="${build}" source="${project.java.version}" debug="true" encoding="${encoding}">
+			<classpath refid="mypath" />
+		</javac>
+
+		<copy todir="${build}">
+			<fileset dir="TDD2019OWNTESTS/src">
+				<include name="**/*.story" />
+			</fileset>
+		</copy>
+	</target>
+
+	<target name="tests" description="test de l'application web à l'aide de JUnit" depends="build">
+		<taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
+			<classpath path="lib/jacocoant.jar" />
+		</taskdef>
+		<antcall target="compilepublictests" />
+		<available property="private.tests.found" file="TDD2019HIDDENTESTS/src" type="dir" />
+		<antcall target="compileprivatetests" />
+		<antcall target="compileowntests" />
+		<jacoco:coverage destfile="${sonar.jacoco.reportPaths}">
+			<junit fork="yes" forkmode="once" printsummary="false" haltonfailure="no" failureproperty="tests.failure">
+				<classpath refid="mypath" />
+				<formatter type="plain" usefile="false" />
+				<formatter type="xml" />
+				<batchtest fork="yes" todir="${testreports}">
+					<fileset dir="${build}">
+						<include name="**/TDD*.class" />
+						<include name="**/*Test*.class" />
+						<include name="**/PeterNorvig*.class" />
+						<exclude name="**/AllTests.class" />
+						<exclude name="**/Abstract*.class" />
+					</fileset>
+				</batchtest>
+			</junit>
+		</jacoco:coverage>
+	</target>
+
+	<target name="m1" description="Verification des projets de TDD2019" depends="clean,build,tests">
+	    <subant failonerror="false" target="mutationCoverage">
+	        <fileset dir="." includes="build.xml" />
+	    </subant>
+	</target>
+
+	<!-- Define the SonarQube target -->
+	<target name="sonar" depends="m1" description="Analyse le code avec SonarQube">
+		<taskdef uri="antlib:org.sonar.ant" resource="org/sonar/ant/antlib.xml">
+			<classpath path="lib/sonarqube-ant-task-2.5.jar" />
+		</taskdef>
+		<!-- To avoid analyzing the tests -->
+		<delete dir="${build}" />
+		<mkdir dir="${build}" />
+		<antcall target="build" />
+		<!-- Execute the SonarQube analysis -->
+		<sonar:sonar />
+		<fail message="Il reste des tests qui ne passent pas !" if="tests.failure" />
+	</target>
+
+	<taskdef name="pitest" classname="org.pitest.ant.PitestTask" classpathref="mypath" />
+    <target name="mutationCoverage">
+        <pitest
+              pitClasspath="mypath"
+              classPath="mypath"
+              targetClasses="migl.*"
+              excludedMethods="*hashCode()"
+              excludedClasses="*Test*,*Eval*"
+              targetTests="migl.*"
+              reportDir="${testreports}"
+              outputFormats="XML,HTML"
+              sourceDir="${src}"/>
+    </target>
+</project>

+ 18 - 0
TDD2019IMPL/checklinks.sh

@@ -0,0 +1,18 @@
+#!/bin/bash
+
+if [ ! -d "TDD2019TESTS" ]; then
+   echo "Adding main public test repository"
+   git submodule add --force https://forge.univ-artois.fr/m1-2018-2019/TDD2019TESTS.git 
+fi
+
+if [ ! -d "TDD2019HIDDENTESTS" ]; then
+   echo "Adding main hidden test repository"
+   git submodule add --force https://forge.univ-artois.fr/root/TDD2019HIDDENTESTS.git 
+fi
+
+if [ ! -d "TDD2019OWNTESTS" ]; then
+   echo "Adding own test repository for $1"
+   git submodule add --force https://forge.univ-artois.fr/$1/TDD2019OWNTESTS.git 
+fi
+
+# git checkout HEAD .gitmodules

BIN
TDD2019IMPL/lib/commons-codec-1.11.jar


BIN
TDD2019IMPL/lib/commons-collections4-4.1.jar


BIN
TDD2019IMPL/lib/commons-io-2.5.jar


BIN
TDD2019IMPL/lib/commons-lang3-3.5.jar


BIN
TDD2019IMPL/lib/freemarker.jar


BIN
TDD2019IMPL/lib/hamcrest-core-1.3.jar


BIN
TDD2019IMPL/lib/jacocoant.jar


BIN
TDD2019IMPL/lib/jbehave-ant-4.1.jar


BIN
TDD2019IMPL/lib/jbehave-core-4.1-javadoc.jar


BIN
TDD2019IMPL/lib/jbehave-core-4.1.jar


BIN
TDD2019IMPL/lib/jbehave-junit-runner-1.2.1-20150529.081438-4.jar


BIN
TDD2019IMPL/lib/jscheme-7.2.jar


BIN
TDD2019IMPL/lib/junit-4.12.jar


BIN
TDD2019IMPL/lib/org.eclipse.jdt.annotation_2.1.100.v20170511-1408.jar


BIN
TDD2019IMPL/lib/paranamer-2.8.jar


BIN
TDD2019IMPL/lib/pitest-1.4.5.jar


BIN
TDD2019IMPL/lib/pitest-ant-1.4.5.jar


BIN
TDD2019IMPL/lib/pitest-entry-1.4.5.jar


BIN
TDD2019IMPL/lib/plexus-utils-3.0.24.jar


BIN
TDD2019IMPL/lib/qualinsight-plugins-sonarqube-smell-api-4.0.0.jar


BIN
TDD2019IMPL/lib/sonarqube-ant-task-2.5.jar


BIN
TDD2019IMPL/org.eclipse.jdt.annotation_2.2.200.v20180921-1416.jar


+ 45 - 0
TDD2019IMPL/src/migl/lisp/Lisp.java

@@ -0,0 +1,45 @@
+package migl.lisp;
+
+/**
+ * A simple abstraction for a lisp interpreter.
+ * 
+ * @author leberre
+ *
+ */
+public interface Lisp {
+
+    /**
+     * Parse a textual lisp expression and cut it into operator and operands for
+     * further evaluation.
+     * 
+     * @param expr
+     * @return a single object or a list of elements
+     * @throws LispError
+     *             if the expression is not a valid Lisp/scheme expression
+     */
+    Object parse(String expr) throws LispError;
+
+    /**
+     * Evaluate the expression returned by the {@link #parse(String)} method.
+     * 
+     * @param ex
+     *            the result of the {@link #parse(String)} method
+     * @return a lisp evaluation of the parameter
+     * @throws LispError
+     *             if the expression cannot be evaluated
+     */
+    Object evaluate(Object ex) throws LispError;
+
+    /**
+     * Evaluate a lisp expression.
+     * 
+     * @param expr
+     *            a lisp expression
+     * @return a
+     * @throws LispError
+     *             if the expression is malformed or cannot be evaluated.
+     */
+    default Object eval(String expr) throws LispError {
+        return evaluate(parse(expr));
+    }
+}

+ 90 - 0
TDD2019IMPL/src/migl/lisp/LispBoolean.java

@@ -0,0 +1,90 @@
+package migl.lisp;
+
+/**
+ * Simple Boolean type for our lisp interpreter.
+ * 
+ * We do not use the classical boolean operators in order to have an easy
+ * translation to and from the lisp representation of Booleans.
+ * 
+ * The Boolean operators are not implemented. They must be applied on the
+ * {@link #value()} of the object.
+ * 
+ * @author leberre
+ *
+ */
+public final class LispBoolean {
+
+    /**
+     * The object representing the true Boolean value.
+     */
+    public static final LispBoolean TRUE = new LispBoolean(true);
+
+    /**
+     * The object representing the false Boolean value.
+     */
+    public static final LispBoolean FALSE = new LispBoolean(false);
+
+    private final boolean value;
+
+    private LispBoolean(boolean value) {
+        this.value = value;
+    }
+
+    /**
+     * Retrieve a Java primitive Boolean value for Boolean reasoning in Java code.
+     * 
+     * @return the corresponding Java's Boolean value.
+     */
+    public boolean value() {
+        return this.value;
+    }
+
+    @Override
+    public int hashCode() {
+        return Boolean.hashCode(value);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof LispBoolean) {
+            return ((LispBoolean) obj).value == value;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return value ? "#t" : "#f";
+    }
+
+    /**
+     * Retrieve a {@link LispBoolean} from a Java primitive Boolean.
+     * 
+     * @param b
+     *            a Boolean value
+     * @return the corresponding {@link LispBoolean} object.
+     */
+    public static LispBoolean valueOf(boolean b) {
+        return b ? TRUE : FALSE;
+    }
+
+    /**
+     * Retrieve a {@link LispBoolean} from its textual representation.
+     * 
+     * @param s
+     *            a textual representation of the boolean value (#t or #f)
+     * @return the corresponding {@link LispBoolean} object.
+     * @throws IllegalArgumentException
+     *             if s does not correspond to a valid textual representation.
+     */
+    public static LispBoolean valueOf(String s) {
+        switch (s.toLowerCase()) {
+        case "#t":
+            return TRUE;
+        case "#f":
+            return FALSE;
+        default:
+            throw new IllegalArgumentException("Not a Boolean");
+        }
+    }
+}

+ 276 - 0
TDD2019IMPL/src/migl/lisp/LispElement.java

@@ -0,0 +1,276 @@
+package migl.lisp;
+
+import java.math.BigInteger;
+import java.util.Map;
+
+import migl.util.Cons;
+
+import java.util.HashMap;
+
+/**
+ * Class pour gérer les élément des expressions Lisp
+ * 
+ * @author Arthur Brandao
+ */
+public class LispElement {
+	
+	/**
+	 * Garde en cache les elements deja créer pour eviter de recreer plusieurs fois les meme elements
+	 */
+	private static Map<Object, LispElement> cache = new HashMap<>();
+
+	/**
+	 * La valeur de l'element
+	 */
+	private final Object value;
+
+	/**
+	 * Constructeur privée pour construire un element à partir de valueOf
+	 * 
+	 * @param val
+	 */
+	private LispElement(Object val) {
+		this.value = val;
+		cache.put(val, this);
+	}
+	
+	/**
+	 * Retourne la valeur de l'element lisp
+	 * @return
+	 */
+	public Object getValue() {
+		return this.value;
+	}
+	
+	/**
+	 * Retourne la valeur d'un element sous forme d'entier
+	 * 
+	 * @throws IllegalStateException Si l'element ne peut pas être converti en BigInteger
+	 * @return
+	 */
+	public BigInteger toInt() {
+		if(this.isInt()) {
+			return (BigInteger) this.value;
+		}
+		throw new IllegalStateException("Not an integer");
+	}
+	
+	/**
+	 * Retourne la valeur d'un element sous forme de nombre
+	 * 
+	 * @throws IllegalStateException Si l'element ne peut pas être converti en Double
+	 * @return
+	 */
+	public double toNumber() {
+		if(this.value.getClass() == BigInteger.class) {
+			BigInteger bi = (BigInteger) this.value;
+			return bi.doubleValue();
+		} else if(this.value.getClass() == Double.class) {
+			return (Double) this.value;
+		}
+		throw new IllegalStateException("Not a number");
+	}
+	
+	/**
+	 * Retourne la valeur d'un element sous forme de boolean
+	 * 
+	 * @throws IllegalStateException Si l'element ne peut pas être converti en boolean
+	 * @return
+	 */
+	public boolean toBoolean() {
+		if(this.isBoolean()) {
+			LispBoolean lb = (LispBoolean) this.value;
+			return lb.value();
+		}
+		throw new IllegalStateException("Not a Boolean");
+	}
+	
+	/**
+	 * Retourne la valeur d'un element sous forme de string
+	 * 
+	 * @throws IllegalStateException Si l'element ne peut pas être converti en String
+	 * @return
+	 */
+	public String toStr() {
+		if(this.isStr()) {
+			return (String) this.value;
+		}
+		throw new IllegalStateException("Not a String");
+	}
+	
+	/**
+	 * Retourne la valeur d'un element sous forme d'une liste
+	 * 
+	 * @throws IllegalStateException
+	 * @return
+	 */
+	public LispList toList() {
+		if(this.isList()) {
+			return (LispList) this.value;
+		}
+		throw new IllegalStateException("Not a List");
+	}
+	
+	/**
+	 * Retourne la valeur d'un element sous forme d'une cons
+	 * 
+	 * @throws IllegalStateException
+	 * @return
+	 */
+	public Cons<?, ?> toCons() {
+		if(this.isCons()) {
+			return (Cons<?, ?>) this.value;
+		}
+		throw new IllegalStateException("Not a Cons");
+	}
+	
+	/**
+	 * Indique si l'element est un entier
+	 * @return
+	 */
+	public boolean isInt() {
+		return this.value.getClass() == BigInteger.class;
+	}
+	
+	/**
+	 * Indique si l'element est nombre (BigInteger ou Double)
+	 * @return
+	 */
+	public boolean isNumber() {
+		return this.isInt() || (this.value.getClass() == Double.class);
+	}
+	
+	/**
+	 * Indique si l'element est boolean
+	 * @return
+	 */
+	public boolean isBoolean() {
+		return this.value.getClass() == LispBoolean.class;
+	}
+	
+	/**
+	 * Indique si l'element est un String
+	 * @return
+	 */
+	public boolean isStr() {
+		return this.value.getClass() == String.class;
+	}
+	
+	/**
+	 * Indique si l'element est une liste
+	 * @return
+	 */
+	public boolean isList() {
+		return this.value.getClass() == LispList.class;
+	}
+	
+	/**
+	 * Indique si l'element est une Cons
+	 * @return
+	 */
+	public boolean isCons() {
+		return this.value.getClass() == Cons.class;
+	}
+
+	@Override
+	public int hashCode() {
+		return this.value.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(obj == null) {
+			return false;
+		} else if(this == obj) {
+			return true;
+		} else if(obj instanceof LispElement) {
+			LispElement other = (LispElement) obj;
+			return this.value.equals(other.value);
+		}
+		return false;
+	}
+
+	@Override
+	public String toString() {
+		return this.value.toString();
+	}
+	
+	/**
+	 * Indique le nombre actuel d'element en cache
+	 * @return
+	 */
+	public static int getCacheSize() {
+		return cache.size();
+	}
+	
+	/**
+	 * Supprime le cache
+	 */
+	public static void clear() {
+		cache.clear();
+	}
+
+	/**
+	 * Parse un element
+	 * 
+	 * @param elt L'element à parser
+	 * @return Un LispElement contenant la valeur extraite
+	 */
+	public static LispElement valueOf(String elt) {
+		try {
+			return generate(new BigInteger(elt));
+		} catch(NumberFormatException ex) {
+			//Rien
+		}
+		try {
+			return generate(Double.valueOf(elt));
+		} catch(NumberFormatException ex) {
+			//Rien
+		}
+		try {
+			return generate(LispBoolean.valueOf(elt));
+		} catch(IllegalArgumentException ex) {
+			//Rien
+		}
+		return generate(elt);
+	}
+	
+	/**
+	 * Genere un LispElement correspondant à l'objet
+	 * 
+	 * @param elt
+	 * @return
+	 */
+	public static LispElement generate(Object elt) {
+		if(elt == null) {
+			return new LispElement(null);
+		}
+		else if(elt.getClass() == LispElement.class) {
+			return (LispElement) elt;
+		} 
+		else if(elt.getClass() == Integer.class) {
+			elt = BigInteger.valueOf((Integer) elt);
+		}
+		else if(elt.getClass() == Boolean.class) {
+			elt = LispBoolean.valueOf((boolean) elt);
+		}
+		else if(elt.getClass() == Long.class) {
+			elt = BigInteger.valueOf((long) elt);
+		}
+		else if(
+				elt.getClass() != BigInteger.class 
+				&& elt.getClass() != Double.class 
+				&& elt.getClass() != LispBoolean.class 
+				&& elt.getClass() != String.class
+				&& elt.getClass() != LispList.class
+				&& elt.getClass() != Cons.class
+				) {
+			throw new IllegalArgumentException("Object class is not a Lisp element");
+		}
+		if(cache.containsKey(elt)) {
+			return cache.get(elt);
+		}
+		return new LispElement(elt);
+	}
+
+}

+ 64 - 0
TDD2019IMPL/src/migl/lisp/LispError.java

@@ -0,0 +1,64 @@
+package migl.lisp;
+
+/**
+ * Generic exception for our lisp interpreter.
+ * 
+ * @author leberre
+ *
+ */
+public class LispError extends Exception {
+	
+	/**
+	 * Message d'erreur à cause d'un mauvais nombre d'argument
+	 */
+	public static final String ERR_NUM_ARG = "Invalid number of operands";
+	
+	/**
+	 * Message d'erreur opération non définie
+	 */
+	public static final String ERR_UNKNOW = " is undefined";
+	
+	/**
+	 * Message d'erreur identifieur invalide
+	 */
+	public static final String ERR_INVALID = " is not a valid identifier";
+
+    /**
+     * Fake serial version UID
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Create a new exception with a message and a cause.
+     * 
+     * @param message
+     *            a detailed message intended to the end user.
+     * @param cause
+     *            the reason of the exception (e.g another exception).
+     */
+    public LispError(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Create a new exception with a message.
+     * 
+     * @param message
+     *            a detailed message intended to the end user.
+     */
+    public LispError(String message) {
+        super(message);
+    }
+
+    /**
+     * Encapsulate a throwable as a LispError.
+     * 
+     * @param cause
+     *            the cause of the issue. The message of the exception will be
+     *            the message of the root cause.
+     */
+    public LispError(Throwable cause) {
+        super(cause);
+    }
+
+}

+ 407 - 0
TDD2019IMPL/src/migl/lisp/LispEval.java

@@ -0,0 +1,407 @@
+package migl.lisp;
+
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+
+import migl.lisp.operator.ComparatorOperator;
+import migl.lisp.operator.ConsOperator;
+import migl.lisp.operator.DefineOperator;
+import migl.lisp.operator.LispOperator;
+import migl.lisp.operator.MathOperator;
+import migl.lisp.operator.MinMaxOperator;
+import migl.util.ConsList;
+import migl.util.ConsListFactory;
+
+/**
+ * Evaluateur lisp
+ * @author Arthur Brandao
+ */
+public class LispEval {
+
+	/**
+	 * Les operateurs gérés par l'interpréteur
+	 */
+	private Map<String, LispOperator> operators = new HashMap<>();
+	
+	/**
+	 * L'interpreteur utilisant cet evaluateur pour les appels récursifs
+	 */
+	private final Lisp interpreter;
+	
+	/**
+	 * L'instance de gestion des variables et des fonctions
+	 */
+	private final DefineOperator define = new DefineOperator();
+
+	/**
+	 * Un element lisp
+	 */
+	private Object lispElt = null;
+
+	/**
+	 * Une liste d'elements lisp
+	 */
+	private ConsList<Object> lispList = null;
+
+	/**
+	 * Creation d'un evaluateur lisp
+	 */
+	public LispEval(Lisp interpreter) {
+		this(interpreter, null);
+	}
+
+	/**
+	 * Creation d'un evaluateur lisp
+	 * @param lisp Un element lisp (Object) ou une liste de lisp (ConsList<Object>)
+	 */
+	public LispEval(Lisp interpreter, Object lisp) {
+		this.interpreter = interpreter;
+		if(lisp != null) {
+			this.setLisp(lisp);
+		}
+		this.setUpOperators();
+	}
+
+	/**
+	 * Change l'objet lisp à evaluer
+	 * @param lisp Un element lisp (Object) ou une liste de lisp (ConsList<Object>)
+	 */
+	@SuppressWarnings("unchecked")
+	public final void setLisp(Object lisp) {
+		if(lisp == null) {
+			throw new IllegalArgumentException("Expression is null");
+		} else if(lisp instanceof ConsList) {
+			this.lispElt = null;
+			this.lispList = (ConsList<Object>) lisp;
+		} else {
+			this.lispElt = lisp;
+			this.lispList = null;
+		}
+	}
+
+	/**
+	 * Définit les opérateurs reconnus par l'évaluateur
+	 */
+	private final void setUpOperators() {
+		operators.put("define", this.define);
+		operators.put("set!", this.define);
+		operators.put("lambda", this.define);
+		ConsOperator cons = new ConsOperator();
+		operators.put("cons", cons);
+		operators.put("car", cons);
+		operators.put("cdr", cons);
+		ComparatorOperator comp = new ComparatorOperator();
+		operators.put(">", comp);
+		operators.put(">=", comp);
+		operators.put("<", comp);
+		operators.put("<=", comp);
+		operators.put("=", comp);
+		MinMaxOperator minMax = new MinMaxOperator();
+		operators.put("min", minMax);
+		operators.put("max", minMax);
+		MathOperator math = new MathOperator();
+		operators.put("cbrt", math);
+		operators.put("ceil", math);
+		operators.put("floor", math);
+		operators.put("log10", math);
+		operators.put("cos", math);
+		operators.put("rint", math);
+		operators.put("round", math);
+		operators.put("signum", math);
+		operators.put("quote", (eval, op, lisp) -> {
+			if(lisp.size() != 1) {
+				throw new LispError(LispError.ERR_NUM_ARG);
+			}
+			return LispElement.generate(lisp.car().toString());
+		});
+		operators.put("if", (eval, op, lisp) -> {
+			if(lisp.size() != 3) {
+				throw new LispError(LispError.ERR_NUM_ARG);
+			}
+			if(this.getElement(lisp.car()).toBoolean()) {
+				return eval.getElement(lisp.cdr().car());
+			} else {
+				return eval.getElement(lisp.cdr().cdr().car());
+			}
+		});
+		operators.put("not", (eval, op, lisp) -> {
+			if(lisp.size() != 1) {
+				throw new LispError(LispError.ERR_NUM_ARG);
+			}
+			boolean result = !eval.getElement(lisp.car()).toBoolean();
+			return LispElement.generate(result);
+		});
+		operators.put("and", (eval, op, lisp) -> {
+			boolean result = true;
+			while(!lisp.isEmpty()) {
+				result = result && eval.getElement(lisp.car()).toBoolean();
+				lisp = lisp.cdr();
+			}
+			return LispElement.generate(result);
+		});
+		operators.put("or", (eval, op, lisp) -> {
+			boolean result = false;
+			while(!lisp.isEmpty()) {
+				result = result || eval.getElement(lisp.car()).toBoolean();
+				lisp = lisp.cdr();
+			}
+			return LispElement.generate(result);
+		});
+		operators.put("+", (eval, op, lisp) -> {
+			BigInteger resultInt = new BigInteger("0");
+			while(!lisp.isEmpty()){
+				LispElement eltInt = eval.getElement(lisp.car());
+				if(eltInt.getValue().getClass() != BigInteger.class) break;
+				resultInt = resultInt.add(eltInt.toInt());
+				lisp = lisp.cdr();
+			}
+			//Si on finit la liste avec que des entier on retourne
+			if(lisp.isEmpty()) return LispElement.generate(resultInt);
+			//Sinon on continue en passant en double
+			double result = resultInt.doubleValue();
+			while(!lisp.isEmpty()) {
+				LispElement elt = eval.getElement(lisp.car());
+				result += elt.toNumber();
+				lisp = lisp.cdr();
+			}
+			return LispElement.generate(result);
+		});
+		operators.put("*", (eval, op, lisp) -> {
+			BigInteger resultInt = new BigInteger("1");
+			while(!lisp.isEmpty()){
+				LispElement eltInt = eval.getElement(lisp.car());
+				if(eltInt.getValue().getClass() != BigInteger.class) break;
+				resultInt = resultInt.multiply(eltInt.toInt());
+				lisp = lisp.cdr();
+			}
+			//Si on finit la liste avec que des entier on retourne
+			if(lisp.isEmpty()) return LispElement.generate(resultInt);
+			//Sinon on continue en passant en double
+			double result = resultInt.doubleValue();
+			while(!lisp.isEmpty()) {
+				LispElement elt = eval.getElement(lisp.car());
+				result *= elt.toNumber();
+				lisp = lisp.cdr();
+			}
+			return LispElement.generate(result);
+		});
+		operators.put("-", (eval, op, lisp) -> {
+			switch(lisp.size()) {				
+			case 1:
+				LispElement elt = eval.getElement(lisp.car());
+				if(elt.isInt()) {
+					return LispElement.generate(elt.toInt().multiply(new BigInteger("-1")));
+				}
+				return LispElement.generate(elt.toNumber() * -1); //Pb pitest qui remplace * par / or *-1 == /-1
+			case 2:
+				LispElement elt1 = eval.getElement(lisp.car());
+				LispElement elt2 = eval.getElement(lisp.cdr().car());
+				if(elt1.isInt() && elt2.isInt()) {
+					return LispElement.generate(elt1.toInt().subtract(elt2.toInt()));
+				}
+				return LispElement.generate(elt1.toNumber() - elt2.toNumber());
+			default:
+				throw new LispError(LispError.ERR_NUM_ARG);
+			}
+		});
+		operators.put("/", (eval, op, lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError(LispError.ERR_NUM_ARG);
+			}
+			LispElement elt1 = eval.getElement(lisp.car());
+			LispElement elt2 = eval.getElement(lisp.cdr().car());
+			if(elt2.toNumber() == 0) {
+				throw new LispError("Division by zero");
+			}
+			if(elt1.isInt() && elt2.isInt()) {
+				return LispElement.generate(elt1.toInt().divide(elt2.toInt()));
+			}
+			return LispElement.generate(elt1.toNumber() / elt2.toNumber());
+		});
+		operators.put("abs", (eval, op, lisp) -> {
+			if(lisp.size() != 1) {
+				throw new LispError(LispError.ERR_NUM_ARG);
+			}
+			LispElement le = eval.getElement(lisp.car());
+			if(le.isInt()) {
+				return LispElement.generate(le.toInt().abs());
+			}
+			return LispElement.generate(Math.abs(le.toNumber()));
+		});
+		operators.put("pow", (eval, op, lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError(LispError.ERR_NUM_ARG);
+			}
+			return LispElement.generate(Math.pow(eval.getElement(lisp.car()).toNumber(), eval.getElement(lisp.cdr().car()).toNumber()));
+		});
+		operators.put("list", (eval, op, lisp) -> {
+			LispList list = LispList.nil();
+			while(!lisp.isEmpty()) {
+				list.append(eval.getElement(lisp.car()));
+				lisp = lisp.cdr();
+			}
+			return LispElement.generate(list);
+		});
+		operators.put("map", (eval, op, lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError(LispError.ERR_NUM_ARG);
+			}
+			//Regarde si le parametre est une fonction lambda
+			if(!eval.getDefine().isLambda(lisp.car())) {
+				throw new LispError(lisp.car() + LispError.ERR_INVALID);
+			}
+			//Regarde si le second parametre est une expression lisp à evaluer
+			if(!(lisp.cdr().car() instanceof ConsList)) {
+				throw new LispError(lisp.cdr().car() + LispError.ERR_INVALID);
+			}
+			//Evalue l'expression la valeurs des parametres
+			@SuppressWarnings("unchecked")
+			LispElement res = eval.evaluateList((ConsList<Object>) lisp.cdr().car());
+			if(!res.isList()) {
+				return LispElement.generate(LispList.nil());
+			}
+			//Pour chaque element de la liste evalue la fonction
+			LispList result = LispList.nil();
+			LispList list = res.toList();
+			for(int i = 0; i < list.size(); i++) {
+				ConsList<Object> cl = ConsListFactory.asList(lisp.car(), list.get(i));
+				result.append(eval.evaluateList(cl));
+			}
+			return LispElement.generate(result);
+		});
+	}
+
+	/**
+	 * Evalue l'element lisp
+	 * @return L'element retourner par l'évaluation
+	 * @throws LispError
+	 */
+	public LispElement evaluate() throws LispError {
+		if(this.lispElt != null) {
+			return this.evalElt();
+		} else if(this.lispList != null) {
+			return this.evaluateList();
+		}
+		return null;
+	}
+
+	/**
+	 * Evalue un element
+	 * @return L'element retourner par l'évaluation
+	 * @throws LispError
+	 */
+	public LispElement evalElt() throws LispError {
+		try {
+			return this.getElement(this.lispElt);
+		} catch (IllegalArgumentException ex) {
+			throw new LispError(ex.getMessage(), ex);
+		}
+	}
+
+	/**
+	 * Evalue une liste d'elements lisp
+	 * @return L'element retourner par l'évaluation
+	 * @throws LispError
+	 */
+	public LispElement evaluateList() throws LispError {
+		return this.evaluateList(this.lispList);
+	}
+
+	/**
+	 * Evalue un liste d'élément lisp parser dans un ConsList
+	 * 
+	 * @param lisp La liste parser {@link #parse(String)}
+	 * @return Valeur évaluer
+	 * @throws LispError
+	 */
+	@SuppressWarnings("unchecked")
+	public LispElement evaluateList(ConsList<Object> lisp) throws LispError {
+		//Expression vide
+		if(lisp.isEmpty()) {
+			return LispElement.generate("()");
+		}
+		//LCPF
+		if(lisp.car() instanceof ConsList) {
+			LispElement elt = this.evaluateList((ConsList<Object>) lisp.car());
+			ConsList<Object> cl = ConsListFactory.asList(elt.toStr(), lisp.cdr().car());
+			return this.evaluateList(cl);
+		}
+		//Recherche l'operateur
+		String operator = LispElement.generate(lisp.car()).toStr();
+		LispOperator op = this.operators.get(operator);
+		if(op == null) {
+			//On suppose que l'operateur est une expression lambda
+			return this.operators.get("lambda").apply(this, operator, lisp.cdr());
+		}
+		try {
+			return op.apply(this, operator, lisp.cdr());
+		} catch (IllegalStateException ex) {
+			throw new LispError(ex.getMessage(), ex);
+		} catch (IllegalArgumentException ex) {
+			throw new LispError("List Lisp malformed: " + ex.getMessage(), ex);
+		}
+	}
+
+	/**
+	 * Verifie que le nom pour une variable n'est pas interdit
+	 * 
+	 * @param name Nom pour la variable
+	 * @throws LispError Si le nom n'est pas valide
+	 */
+	public void verifyForbiddenName(String name) throws LispError {
+		//Verifie que ce n'est pas une valeur (double, bool, ...)
+		try {
+			LispElement.valueOf(name).toStr();
+		} catch (IllegalStateException ex) {
+			throw new LispError(name + LispError.ERR_INVALID, ex);
+		}
+		//Verifie que ce n'est pas le nom d'un operateur
+		if(this.operators.containsKey(name)) {
+			throw new LispError(name + LispError.ERR_INVALID);
+		}
+	}
+	
+	/**
+	 * Récupère un élément dans la liste lisp
+	 * Si l'element est une liste elle seras alors analyser
+	 * 
+	 * @param elt L'element à récupérer
+	 * @return L'element ou le resultat de l'analyse si l'element est une liste
+	 * @throws LispError
+	 */
+	@SuppressWarnings("unchecked")
+	public LispElement getElement(Object elt) throws LispError {
+		if(elt instanceof ConsList) {
+			return this.evaluateList((ConsList<Object>) elt);
+		} else if(elt instanceof String) {
+			//Si c'est un string qui n'est pas un nom reservé
+			String str = (String) elt;
+			boolean skip = false;
+			try {
+				this.verifyForbiddenName(str);
+			} catch (LispError ex) {
+				skip = true;
+			}
+			if(!skip) return this.define.eval(elt);
+		}
+		return LispElement.generate(elt);
+	}
+	
+	/**
+	 * Retourne l'interpreteur utilisant cet évaluateur
+	 * @return
+	 */
+	public Lisp getInterpreter() {
+		return this.interpreter;
+	}
+	
+	/**
+	 * Retourne l'instance de gestion des variables et des fonctions
+	 * @return
+	 */
+	public DefineOperator getDefine() {
+		return this.define;
+	}
+	
+}

+ 39 - 0
TDD2019IMPL/src/migl/lisp/LispFactory.java

@@ -0,0 +1,39 @@
+package migl.lisp;
+
+
+/**
+ * Simple factory to access the interpreter implementation.
+ * 
+ * @author leberre
+ *
+ */
+public class LispFactory {
+	
+	private static Lisp lastInterpreter;
+
+    private LispFactory() {
+        // do nothing
+    }
+
+    /**
+     * Create new instance of the interpreter.
+     * 
+     * @return a new lisp interpreter.
+     */
+    public static Lisp makeIntepreter() {
+    	LispElement.clear();
+    	return lastInterpreter = new LispImpl();
+    }
+    
+    /**
+     * Get last instance of the interpreter.
+     * 
+     * @return a new lisp interpreter.
+     */
+    public static Lisp getInterpreter() {
+    	if(lastInterpreter == null) {
+    		lastInterpreter = new LispImpl();
+    	}
+        return lastInterpreter;
+    }
+}

+ 40 - 0
TDD2019IMPL/src/migl/lisp/LispImpl.java

@@ -0,0 +1,40 @@
+package migl.lisp;
+
+public class LispImpl implements Lisp {
+	
+	private final LispParser parser = new LispParser();
+	
+	private final LispEval eval = new LispEval(this);
+	
+	@Override
+	public Object parse(String expr) throws LispError {
+		this.parser.setExpr(expr);
+		if(!this.parser.verify()) {
+			throw new LispError("Invalid Format");
+		}
+		return this.parser.parse();
+	}
+
+	@Override
+	public Object evaluate(Object lisp) throws LispError {
+		this.eval.setLisp(lisp);
+		return this.eval.evaluate();
+	}
+	
+	/**
+	 * Retourne l'instance utilisée pour analyser les epxressions lisp
+	 * @return
+	 */
+	public LispParser getParser() {
+		return this.parser;
+	}
+	
+	/**
+	 * Retourne l'instance utilisée pour évaluer les epxressions lisp
+	 * @return
+	 */
+	public LispEval getEval() {
+		return this.eval;
+	}
+
+}

+ 139 - 0
TDD2019IMPL/src/migl/lisp/LispList.java

@@ -0,0 +1,139 @@
+package migl.lisp;
+
+import migl.util.ConsList;
+import migl.util.ConsListFactory;
+
+public class LispList{
+	
+	/**
+	 * ConsList pour stocker les elements de la liste
+	 */
+	private ConsList<Object> list;
+	
+	/**
+	 * Création d'une liste vide
+	 */
+	private LispList() {
+		this.list = ConsListFactory.nil();
+	}
+	
+	/**
+	 * Création d'une liste non vide
+	 * @param list
+	 */
+	private LispList(ConsList<Object> list) {
+		this.list = list;
+	}
+	
+	/**
+	 * Ajoute un element à la fin de la liste
+	 * @param elt
+	 */
+	public LispList append(Object elt) {
+		this.list = this.list.append(elt);
+		return this;
+	}
+	
+	/**
+	 * Ajoute un element au debut de la liste
+	 * @param elt
+	 */
+	public LispList prepend(Object elt) {
+		this.list = this.list.prepend(elt);
+		return this;
+	}
+	
+	/**
+	 * Récupère un element
+	 * @param index La position de l'element
+	 * @return
+	 */
+	public Object get(int index) {
+		LispList l = this.getSubList(index);
+		if(l == null) {
+			return null;
+		}
+		return l.list.car();
+	}
+	
+	/**
+	 * Récupére une sous liste
+	 * @param index La position de debut de la sous liste
+	 * @return
+	 */
+	public LispList getSubList(int index) {
+		if(this.list.size() <= index || index < 0) {
+			return null;
+		}
+		ConsList<Object> cl = this.list;
+		for(int i = 0; i < index; i++) {
+			cl = cl.cdr();
+		}
+		return new LispList(cl);
+	}
+	
+	/**
+	 * Retourne la taille de la liste
+	 * @return
+	 */
+	public int size() {
+		return this.list.size();
+	}
+	
+	/**
+	 * Indique si la liste est vide ou non
+	 * @return
+	 */
+	public boolean isEmpty() {
+		return this.list.isEmpty();
+	}
+	
+	@Override
+	public String toString() {
+		return this.list.toString();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		} else  if(obj == null) {
+			return false;
+		} else if(obj instanceof LispList) {
+			LispList l = (LispList) obj;
+			return this.list.equals(l.list);
+		}
+		return false;
+	}
+	
+	@Override
+	public int hashCode() {
+		return this.list.hashCode();
+	}
+	
+	/**
+	 * Factory pour créer des listes vides
+	 * @return
+	 */
+	public static LispList nil() {
+		return new LispList();
+	}
+	
+	/**
+	 * Factory pour créer des listes à partir de String (ex : (1 2 3 4))
+	 * @param expr
+	 * @return
+	 */
+	public static LispList valueOf(String expr) {
+		ConsList<Object> cl = ConsListFactory.nil();
+		String[] tmp = expr.trim().split("[ |\t]");
+		for(String str : tmp) {
+			str = str.replaceAll("[\\(|\\)]", "").trim();
+			if(str.length() > 0) {
+				cl = cl.append(str);
+			}
+		}
+		return new LispList(cl);
+	}
+
+}

+ 224 - 0
TDD2019IMPL/src/migl/lisp/LispParser.java

@@ -0,0 +1,224 @@
+package migl.lisp;
+
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import migl.util.ConsList;
+import migl.util.ConsListFactory;
+
+/**
+ * Analyseur Lisp
+ * @author Arthur Brandao
+ */
+public class LispParser {
+	
+	/**
+	 * Regex d'un element lisp
+	 */
+	private static final String REGEX_LISP_ELEMENT = "[ |\t]*[A-Za-z0-9\\.\\+\\-\\/\\*<>=#]+[ |\t]*";
+	
+	/**
+	 * Regex d'une liste d'elements lisp
+	 */
+	private static final String REGEX_LISP_LIST = "\\(([ |\t]*[A-Za-z0-9\\.\\+\\-\\/\\*<>=#!]+[ |\t]*)*\\)";
+	
+	/**
+	 * L'expression à analyser
+	 */
+	private String expr;
+	
+	/**
+	 * L'expression exploser pour l'analyse les données
+	 */
+	private Queue<String> explode = new LinkedList<>();
+	
+	/**
+	 * Création d'un analyseur lisp
+	 */
+	public LispParser() {
+		this.setExpr("");
+	}
+	
+	/**
+	 * Création d'un analyseur lisp
+	 * @param lispExpr
+	 */
+	public LispParser(String lispExpr) {
+		this.setExpr(lispExpr);
+	}
+	
+	/**
+	 * Change l'expression lisp à analyser
+	 * @param lispExpr
+	 */
+	public final void setExpr(String lispExpr) {
+		if(lispExpr == null) {
+			throw new IllegalArgumentException("Expression is null");
+		}
+		this.expr = lispExpr.trim();
+	}
+	
+	/* --- Verification de l'expression --- */
+	
+	/**
+	 * Verifie que le format d'un String correspond bien à une expression Lisp
+	 * 
+	 * @param expr Le String à examiner
+	 * @return
+	 */
+	public boolean verify() {
+		//Pas vide
+		if(this.expr.length() == 0) {
+			return false;
+		}
+		//Liste ou element
+		if(this.expr.charAt(0) == '(') {
+			return this.verifyList();
+		}
+		return this.verifyElement();
+	}
+	
+	/**
+	 * Verifie que le format d'un String correspond bien à un element Lisp
+	 * 
+	 * @param expr Le String à examiner
+	 * @return
+	 */
+	private boolean verifyElement() {
+		Pattern p = Pattern.compile(REGEX_LISP_ELEMENT);
+		Matcher m = p.matcher(this.expr);
+		return m.find();
+	}
+	
+	/**
+	 * Verifie que le format d'un String correspond bien à une liste Lisp
+	 * 
+	 * @param lispExpr Le String à examiner
+	 * @return
+	 */
+	private boolean verifyList() {
+		return this.verifyList(this.expr);
+	}
+	
+	/**
+	 * Verifie que le format d'un String correspond bien à une liste Lisp
+	 * 
+	 * @param lispExpr Le String à examiner
+	 * @return
+	 */
+	private boolean verifyList(String lispExpr) {
+		Pattern p = Pattern.compile(REGEX_LISP_LIST);
+		Matcher m = p.matcher(lispExpr);
+		//Si pas de correspondance
+		if(!m.find()) {
+			return false;
+		} 
+		//Si toute la chaine
+		else if(m.end() - m.start() == lispExpr.length()) {
+			return true;
+		} 
+		//Si commence au debut mais finit avant la fin il y a alors des elements hors de la liste
+		else if(m.start() == 0) {
+			return false;
+		} 
+		//Si il y a une liste dans la liste
+		else {
+			StringBuilder builder = new StringBuilder();
+			builder.append(lispExpr.substring(0, m.start())).append("list").append(lispExpr.substring(m.end()));
+			return this.verifyList(builder.toString());
+		}
+	}
+	
+	/* --- Parse les elements --- */
+	
+	/**
+	 * Analyse les elements d'une expression lisp
+	 * @return
+	 * @throws LispError
+	 */
+	public Object parse() throws LispError {
+		//Remplace les nil par ()
+		String lispExpr = this.expr.replaceAll(" nil ", " () ")
+				.replaceAll("\\(nil ", "(() ")
+				.replaceAll(" nil\\)", " ())");
+		//Traitement de la chaine pour l'analyer
+		this.explode(lispExpr);
+		//Analyse le type d'expression
+		String val = this.explode.poll();
+		if("(".equals(val)){
+			return this.parseList();
+		} else {
+			//Element seul
+			if(this.explode.size() > 0) {
+				throw new LispError("Invalid Format");
+			}
+			return LispElement.valueOf(val).getValue();
+		}
+	}
+	
+	/**
+	 * Separe les différents elements d'une expression lisp pour l'analyse
+	 * @param lispExpr
+	 */
+	private void explode(String lispExpr) {
+		String[] tmp = lispExpr.trim().split("[ |\t]");
+		for(String str : tmp) {
+			char[] charArray = str.toCharArray();
+			StringBuilder builder = new StringBuilder();
+			for(char c : charArray) {
+				if(c == '(') {
+					//Si il y a une chaine dans le builder à mettre avant
+					if(builder.length() != 0) {
+						this.explode.add(builder.toString());
+						builder = new StringBuilder();
+					}
+					this.explode.add("" + c);
+				} else if(c == ')') {
+					//Si il y a une chaine dans le builder à mettre avant
+					if(builder.length() != 0) {
+						this.explode.add(builder.toString());
+						builder = new StringBuilder();
+					}
+					this.explode.add("" + c);
+				} else {
+					builder.append(c);
+				}
+			}
+			//Si il reste une chaine dans le builder à la fin
+			if(builder.length() != 0) {
+				this.explode.add(builder.toString());
+			}
+		}
+	}
+	
+	/**
+	 * Analyse la liste d'elements
+	 * @return
+	 */
+	private Object parseList() {
+		ConsList<Object> list = ConsListFactory.nil();
+		String val = this.explode.poll();
+		while(!")".equals(val)) {
+			if("(".equals(val)) {
+				list = list.append(this.parseList());
+			} else {
+				list = list.append(LispElement.valueOf(val).getValue());
+			}
+			val = this.explode.poll();
+		}
+		return list;
+	}
+	
+	/* --- Getter --- */
+	
+	/**
+	 * Retourne l'expression analyser
+	 * @return
+	 */
+	public String getExpression() {
+		return this.expr;
+	}
+
+}

+ 44 - 0
TDD2019IMPL/src/migl/lisp/REPL.java

@@ -0,0 +1,44 @@
+package migl.lisp;
+
+import java.util.Scanner;
+
+/**
+ * A very basic Read Eval Print Loop for your interpreter.
+ * 
+ * It is made available to let you play with your work and even to try running
+ * real lisp program with it.
+ * 
+ * @author leberre
+ *
+ */
+public class REPL {
+
+    private REPL() {
+        // to prevent instantiation
+    }
+
+    public static void main(String[] args) {
+        // It would be nice to support expression history as in most common shells.
+        // However, it appears that it is not that simple to implement. MR welcome.
+
+        Lisp lisp = LispFactory.makeIntepreter();
+        try (Scanner scanner = new Scanner(System.in, "UTF8")) {
+            System.out.println("My super own Lisp/Scheme interpreter 2019");
+            System.out.println("Enter a valid Lisp expression followed by Enter. type 'quit' to exit.");
+            System.out.print("> ");
+            while (scanner.hasNext()) {
+                String line = scanner.nextLine();
+                if ("quit".equalsIgnoreCase(line)) {
+                    System.out.println("Bye.");
+                    break;
+                }
+                try {
+                    System.out.println(lisp.eval(line));
+                } catch (LispError le) {
+                    System.out.println("Error: " + le.getMessage());
+                }
+                System.out.print("> ");
+            }
+        }
+    }
+}

+ 50 - 0
TDD2019IMPL/src/migl/lisp/operator/ComparatorOperator.java

@@ -0,0 +1,50 @@
+package migl.lisp.operator;
+
+import migl.lisp.LispElement;
+import migl.lisp.LispError;
+import migl.lisp.LispEval;
+import migl.util.ConsList;
+
+public class ComparatorOperator implements LispOperator {
+
+	@Override
+	public LispElement apply(LispEval eval, String operator, ConsList<Object> lisp) throws LispError {
+		if(lisp.size() == 0) {
+			throw new LispError(LispError.ERR_NUM_ARG);
+		}
+		boolean result = true;
+		boolean first = true;
+		double value = 0;
+		while(!lisp.isEmpty()) {
+			if(first) {
+				value = eval.getElement(lisp.car()).toNumber();
+				first = false;
+			} else {
+				double temp = eval.getElement(lisp.car()).toNumber();
+				switch(operator) {
+					case ">":
+						result = result && (value > temp);
+						break;
+					case ">=":
+						result = result && (value >= temp);
+						break;
+					case "<":
+						result = result && (value < temp);
+						break;
+					case "<=":
+						result = result && (value <= temp);
+						break;
+					case "=":
+						result = result && (value == temp);
+						break;
+					default:
+						throw new LispError(operator + LispError.ERR_UNKNOW);
+				}
+				value = temp;
+			}
+			lisp = lisp.cdr();
+		}
+		return LispElement.generate(result);
+	}
+
+}

+ 79 - 0
TDD2019IMPL/src/migl/lisp/operator/ConsOperator.java

@@ -0,0 +1,79 @@
+package migl.lisp.operator;
+
+import migl.lisp.LispElement;
+import migl.lisp.LispError;
+import migl.lisp.LispEval;
+import migl.lisp.LispList;
+import migl.util.Cons;
+import migl.util.ConsList;
+
+public class ConsOperator implements LispOperator {
+
+	@Override
+	public LispElement apply(LispEval eval, String operator, ConsList<Object> lisp) throws LispError {
+		switch(operator) {
+			case "cons":
+				return this.cons(eval, lisp);
+			case "car":
+				return this.car(eval, lisp);
+			case "cdr":
+				return this.cdr(eval, lisp);
+			default:
+				throw new LispError(operator + LispError.ERR_UNKNOW);
+		}
+	}
+	
+	public LispElement cons(LispEval eval, ConsList<Object> lisp) throws LispError {
+		if(lisp.size() != 2) {
+			throw new LispError(LispError.ERR_NUM_ARG);
+		}
+		if(lisp.cdr().car() instanceof ConsList) {
+			//Recup + evaluation de la liste
+			String listStr = eval.getElement(lisp.cdr().car()).toString();
+			LispList list = LispList.valueOf(listStr);
+			list.prepend(eval.getElement(lisp.car()).getValue());
+			return LispElement.generate(list);
+		} else {
+			LispElement elt = eval.getElement(lisp.car());
+			Cons<LispElement, Object> c = new Cons<>(elt, lisp.cdr().car());
+			return LispElement.generate(c);
+		}
+	}
+	
+	public LispElement car(LispEval eval, ConsList<Object> lisp) throws LispError {
+		if(lisp.size() != 1) {
+			throw new LispError(LispError.ERR_NUM_ARG);
+		}
+		LispElement elt = eval.getElement(lisp.car());
+		if(elt.isList()) {
+			LispList list = elt.toList();
+			if(list.size() < 1) {
+				return  LispElement.generate(LispList.nil());
+			}
+			return LispElement.generate(list.get(0));
+		} else if(elt.isCons()) {
+			return LispElement.generate(elt.toCons().left());
+		} else {
+			throw new LispError(elt + LispError.ERR_INVALID);
+		}
+	}
+	
+	public LispElement cdr(LispEval eval, ConsList<Object> lisp) throws LispError {
+		if(lisp.size() != 1) {
+			throw new LispError(LispError.ERR_NUM_ARG);
+		}
+		LispElement elt = eval.getElement(lisp.car());
+		if(elt.isList()) {
+			LispList list = elt.toList();
+			if(list.size() < 2) {
+				return  LispElement.generate(LispList.nil());
+			}
+			return LispElement.generate(list.getSubList(1));
+		} else if(elt.isCons()) {
+			return LispElement.generate(elt.toCons().right());
+		} else {
+			throw new LispError(elt + LispError.ERR_INVALID);
+		}
+	}
+
+}

+ 247 - 0
TDD2019IMPL/src/migl/lisp/operator/DefineOperator.java

@@ -0,0 +1,247 @@
+package migl.lisp.operator;
+
+import java.util.Map;
+import java.util.Random;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import migl.lisp.Lisp;
+import migl.lisp.LispElement;
+import migl.lisp.LispError;
+import migl.lisp.LispEval;
+import migl.util.ConsList;
+import migl.util.ConsListFactory;
+
+public class DefineOperator implements LispOperator {
+	
+	/**
+	 * Taille des nom aléatoire générés
+	 */
+	private static final int RANDOM_NAME_LENGTH = 8;
+
+	/**
+	 * Tableau des variables et fonctions définit
+	 */
+	private final Map<String, ConsList<Object>> define = new HashMap<>();
+	
+	/**
+	 * Liste des nom de variables/fonctions temporaires
+	 */
+	private final ArrayList<String> tmp = new ArrayList<>();
+
+	@Override
+	public LispElement apply(LispEval eval, String operator, ConsList<Object> lisp) throws LispError {
+		switch(operator) {
+			case "define":
+				return this.define(eval, lisp);
+			case "set!":
+				return this.set(lisp);
+			case "lambda":
+				String name = this.generateRandomName();
+				ConsList<Object> lambda = ConsListFactory.asList("lambda", lisp.car(), lisp.cdr().car());
+				ConsList<Object> cl = ConsListFactory.asList("define", name, lambda);
+				eval.evaluateList(cl);
+				return LispElement.generate(name);
+			default:
+				return this.lambda(eval, operator, lisp);
+		}
+	}
+	
+	/**
+	 * Operateur lisp define
+	 * @param lisp
+	 * @return
+	 * @throws LispError
+	 */
+	@SuppressWarnings("unchecked")
+	private LispElement define(LispEval eval, ConsList<Object> lisp) throws LispError {
+		if(lisp.size() != 2) {
+			throw new LispError(LispError.ERR_NUM_ARG);
+		}
+		//Recup la clef
+		LispElement le = LispElement.generate(lisp.car());
+		String key;
+		try {
+			key = le.toStr();
+		} catch(IllegalStateException ex) {
+			throw new LispError(le.toString() + LispError.ERR_INVALID, ex);
+		}
+		//Verification de sa validité
+		eval.verifyForbiddenName(key);
+		//Si c'est une lambda verification du nombre d'argument
+		if(lisp.cdr().car() instanceof ConsList) {
+			ConsList<Object> cl = (ConsList<Object>) lisp.cdr().car();
+			if(cl.size() != 3) {
+				throw new LispError(LispError.ERR_NUM_ARG);
+			}
+		}
+		//Ajoute dans la map
+		this.define.put(key, lisp.cdr());
+		//Evalue pour le retour
+		return eval(lisp.cdr());
+	}
+
+	/**
+	 * Operateur lisp set!
+	 * @param lisp
+	 * @return
+	 * @throws LispError
+	 */
+	private LispElement set(ConsList<Object> lisp) throws LispError {
+		if(lisp.size() != 2) {
+			throw new LispError(LispError.ERR_NUM_ARG);
+		}
+		//Recup la clef
+		String key;
+		try {
+			key = LispElement.generate(lisp.car()).toStr();
+		} catch(IllegalStateException ex) {
+			throw new LispError(ex);
+		}
+		//Regarde si la valeur est deja presente
+		if(!define.containsKey(key)) {
+			throw new LispError(key + LispError.ERR_UNKNOW);
+		}
+		//Ajoute dans la map
+		this.define.put(key, lisp.cdr());
+		//Evalue pour le retour
+		return eval(lisp.cdr());
+	}
+	
+	/**
+	 * Evalue une expression lambda
+	 * @param operator Le nom de l'expression
+	 * @param lisp Les parametres de l'expression
+	 * @return La valeur de l'expression
+	 * @throws LispError
+	 */
+	@SuppressWarnings("unchecked")
+	private LispElement lambda(LispEval eval, String operator, ConsList<Object> lisp) throws LispError {
+		if(!isLambda(operator)) {
+			throw new LispError(operator + LispError.ERR_UNKNOW);
+		}
+		//Recup les infos
+		ConsList<Object> lambda;
+		ConsList<Object> param;
+		try {
+			lambda = (ConsList<Object>) this.define.get(operator).car();
+			param = (ConsList<Object>) lambda.cdr().car();
+			lambda = (ConsList<Object>) lambda.cdr().cdr().car();
+			if(param.size() != lisp.size()) {
+				throw new LispError(LispError.ERR_NUM_ARG);
+			}
+		} catch (Exception ex) {
+			//Lambda mal formée
+			throw new LispError(operator + LispError.ERR_INVALID, ex);
+		}
+		//Remplace les parametres
+		String lispExpr = lambda.toString();
+		while(!param.isEmpty()) {
+			try {
+				//Tentative d'evalutation des arguments
+				LispElement elt = eval.evaluateList((ConsList<Object>) lisp.car());
+				lispExpr = lispExpr.replaceAll(" " + param.car() + " ", " " + elt + " ")
+						.replaceAll("\\(" + param.car() + " ", "\\(" + elt + " ")
+						.replaceAll(" " + param.car() + "\\)", " " + elt + "\\)");
+			} catch (Exception ex) {
+				lispExpr = lispExpr.replaceAll(" " + param.car() + " ", " " + lisp.car() + " ")
+						.replaceAll("\\(" + param.car() + " ", "\\(" + lisp.car() + " ")
+						.replaceAll(" " + param.car() + "\\)", " " + lisp.car() + "\\)");
+			}
+			param = param.cdr();
+			lisp = lisp.cdr();
+		}
+		//Si c'etait une fonction temporaire
+		if(this.tmp.contains(operator)) {
+			this.tmp.remove(operator);
+			this.define.remove(operator);
+		}
+		//Evalue le resultat
+		Lisp interpreter = eval.getInterpreter();
+		return LispElement.generate(interpreter.eval(lispExpr));
+	}
+	
+	/**
+	 * Indique si un Objet est la representation d'une expression lambda
+	 * @param elt L'objet à evaluer
+	 * @return
+	 */
+	@SuppressWarnings("unchecked")
+	public boolean isLambda(Object elt) {
+		if(!(elt instanceof String)) {
+			return false;
+		}
+		String key = (String) elt;
+		ConsList<Object> cl = this.define.get(key);
+		if(cl == null) {
+			return false;
+		}
+		if(!(cl.car() instanceof ConsList)) {
+			return false;
+		}
+		cl = (ConsList<Object>) cl.car();
+		try {
+			return "lambda".equals(LispElement.generate(cl.car()).toStr());
+		} catch (IllegalStateException ex) {
+			return false;
+		}
+	}
+	
+	/**
+	 * Evalue un objet
+	 * @param elt
+	 * @return
+	 * @throws LispError
+	 */
+	@SuppressWarnings("unchecked")
+	public LispElement eval(Object elt) throws LispError {
+		if(elt instanceof ConsList) {
+			return eval((ConsList<Object>) elt);
+		}
+		//Recup la valeur de l'element
+		LispElement lelt = LispElement.generate(elt);
+		String key;
+		try {
+			key = lelt.toStr();
+		} catch(IllegalStateException ex) {
+			throw new LispError(lelt.toString() + LispError.ERR_UNKNOW, ex);
+		}
+		//Recup la valeur dans la map
+		ConsList<Object> cl = define.get(key);
+		if(cl == null) {
+			//Si aucune valeur alors erreur
+			throw new LispError(key + LispError.ERR_UNKNOW);
+		}
+		//ToDo verifier si ce n'est pas une lambda expression
+		return LispElement.generate(cl.car());
+	}
+	
+	/**
+	 * Evalue une liste
+	 * @param lisp
+	 * @return
+	 */
+	public LispElement eval(ConsList<Object> lisp) {
+		if(lisp.car() instanceof ConsList) {
+			String res = lisp.car().toString();
+			return LispElement.generate(res.substring(1, res.length() - 1));
+		}
+		return LispElement.generate(lisp.car());
+	}
+	
+	/**
+	 * Generation d'un string aleatoire
+	 * @return
+	 */
+	public String generateRandomName() {
+		Random rand = new Random();
+		StringBuilder builder = new StringBuilder();
+		for(int i = 0; i < RANDOM_NAME_LENGTH; i++) {
+			builder.append((char) (rand.nextInt(26) + 97));
+		}
+		String str = builder.toString();
+		this.tmp.add(str);
+		return str;
+	}
+
+}

+ 26 - 0
TDD2019IMPL/src/migl/lisp/operator/LispOperator.java

@@ -0,0 +1,26 @@
+package migl.lisp.operator;
+
+import migl.lisp.LispElement;
+import migl.lisp.LispError;
+import migl.lisp.LispEval;
+import migl.util.ConsList;
+
+/**
+ * Implementation d'un operateur lisp
+ * 
+ * @author Arthur Brandao
+ */
+@FunctionalInterface
+public interface LispOperator {
+
+	/**
+	 * Applique l'operateur lisp sur une liste
+	 * @param L'instance à utiliser pour évaluer l'expression
+	 * @param operator Symbole de l'operateur
+	 * @param lisp Liste d'element à traiter sans le symbole de l'operateur
+	 * @return
+	 * @throws LispError
+	 */
+	LispElement apply(LispEval eval, String operator, ConsList<Object> lisp) throws LispError;
+	
+}

+ 38 - 0
TDD2019IMPL/src/migl/lisp/operator/MathOperator.java

@@ -0,0 +1,38 @@
+package migl.lisp.operator;
+
+import migl.lisp.LispElement;
+import migl.lisp.LispError;
+import migl.lisp.LispEval;
+import migl.util.ConsList;
+
+public class MathOperator implements LispOperator {
+
+	@Override
+	public LispElement apply(LispEval eval, String operator, ConsList<Object> lisp) throws LispError {
+		if(lisp.size() != 1) {
+			throw new LispError(LispError.ERR_NUM_ARG);
+		}
+		LispElement elt = eval.getElement(lisp.car());
+		switch(operator) {
+			case "cbrt":
+				return LispElement.generate(Math.cbrt(elt.toNumber()));
+			case "ceil":
+				return LispElement.generate(Math.ceil(elt.toNumber()));
+			case "floor":
+				return LispElement.generate(Math.floor(elt.toNumber()));
+			case "log10":
+				return LispElement.generate(Math.log10(elt.toNumber()));
+			case "cos":
+				return LispElement.generate(Math.cos(elt.toNumber()));
+			case "rint":
+				return LispElement.generate(Math.rint(elt.toNumber()));
+			case "round":
+				return LispElement.generate(Math.round(elt.toNumber()));
+			case "signum":
+				return LispElement.generate(Math.signum(elt.toNumber()));
+			default:
+				throw new LispError(operator + LispError.ERR_UNKNOW);
+		}
+	}
+
+}

+ 63 - 0
TDD2019IMPL/src/migl/lisp/operator/MinMaxOperator.java

@@ -0,0 +1,63 @@
+package migl.lisp.operator;
+
+import java.math.BigInteger;
+
+import migl.lisp.LispElement;
+import migl.lisp.LispError;
+import migl.lisp.LispEval;
+import migl.util.ConsList;
+
+public class MinMaxOperator implements LispOperator {
+
+	@Override
+	public LispElement apply(LispEval eval, String operator, ConsList<Object> lisp) throws LispError {
+		if(lisp.size() != 2 /* Mettre == 0 Pour nombre infini variable */) {
+			throw new LispError(LispError.ERR_NUM_ARG);
+		}
+		//Initialise avec la 1er valeur
+		LispElement elt = eval.getElement(lisp.car());
+		lisp = lisp.cdr();
+		double result;
+		try {
+			BigInteger res = elt.toInt();
+			//Parcours les elements suivants
+			while(!lisp.isEmpty()) {
+				elt = eval.getElement(lisp.car());
+	            if(elt.getValue().getClass() != BigInteger.class) break;
+	            switch(operator) {
+					case "max":
+						res = res.max(elt.toInt());
+						break;
+					case "min":
+						res = res.min(elt.toInt());
+						break;
+					default:
+						throw new LispError(operator + LispError.ERR_UNKNOW);
+				}
+	            lisp = lisp.cdr();
+			}
+			//Si on finit la liste avec que des entier on retourne
+	        if(lisp.isEmpty()) return LispElement.generate(res);
+	        //Sinon on continue en passant en double
+	        result = res.doubleValue();
+		} catch (Exception ex) {
+			result = elt.toNumber();
+		}
+        while(!lisp.isEmpty()) {
+             double value = eval.getElement(lisp.car()).toNumber();
+             switch(operator) {
+				case "max":
+					result = Math.max(value, result);
+					break;
+				case "min":
+					result = Math.min(value, result);
+					break;
+				default:
+					throw new LispError(operator + LispError.ERR_UNKNOW);
+			}
+            lisp = lisp.cdr();
+        }
+        return LispElement.generate(result);
+	}
+
+}

+ 117 - 0
TDD2019IMPL/src/migl/util/Cons.java

@@ -0,0 +1,117 @@
+package migl.util;
+
+/**
+ * Building block for implementing lists.
+ * 
+ * A "cons" is simply a pair (L,R) holding a specific value on the left hand
+ * side (L) and the right hand side (R).
+ * 
+ * See e.g. {@link https://en.wikipedia.org/wiki/Cons} for details.
+ * 
+ * @author leberre
+ *
+ * @param <L>
+ *            the type of the left hand side of the pair
+ * @param <R>
+ *            the type of the right hand side of the pair
+ */
+public class Cons<L, R> {
+
+    /**
+     * The left hand side of the pair.
+     */
+    private final L left;
+
+    /**
+     * The right hand side of the pair.
+     */
+    private final R right;
+
+    /**
+     * Private default constructor to prevent its use outside the class.
+     */
+    private Cons() {
+        this(null, null);
+    }
+
+    /**
+     * Generic constructor for the cons data structure.
+     * 
+     * @param left
+     *            the left hand side.
+     * @param right
+     *            the right hand side.
+     */
+    public Cons(L left, R right) {
+        this.left = left;
+        this.right = right;
+    }
+
+    /**
+     * Retrieve the left hand side of the pair.
+     * 
+     * @return the left hand side of the pair if any.
+     */
+    public L left() {
+        return left;
+    }
+
+    /**
+     * Retrieve the right hand side of the pair.
+     * 
+     * @return the right hand side of the pair if any.
+     */
+    public R right() {
+        return right;
+    }
+
+    /**
+     * Typical textual "dotted" representation of a cons : ( L . R ).
+     * 
+     * @return a dotted textual representation of the cons pair.
+     */
+    @Override
+    public String toString() {
+        return "(" + left + " . " + right + ")";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((left == null) ? 0 : left.hashCode());
+        return prime * result + ((right == null) ? 0 : right.hashCode());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Cons<?, ?> other = (Cons<?, ?>) obj;
+        if (left == null) {
+            if (other.left != null)
+                return false;
+        } else if (!left.equals(other.left))
+            return false;
+        if (right == null) {
+            if (other.right != null)
+                return false;
+        } else if (!right.equals(other.right))
+            return false;
+        return true;
+    }
+
+    /**
+     * Uses type inference to build an empty cons of the expected type.
+     * 
+     * @return an empty cons of the expected type.
+     */
+    public static final <U, V> Cons<U, V> nil() {
+        return new Cons<>();
+    }
+
+}

+ 76 - 0
TDD2019IMPL/src/migl/util/ConsEmptyList.java

@@ -0,0 +1,76 @@
+package migl.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.function.Function;
+
+public class ConsEmptyList<E> implements ConsList<E> {
+
+	@Override
+	public Iterator<E> iterator() {
+		return new Iterator<E>() {
+			@Override
+			public boolean hasNext() {
+				return false;
+			}
+
+			@Override
+			public E next() {
+				throw new NoSuchElementException("Liste vide");
+			}
+		};
+	}
+
+	@Override
+	public ConsList<E> prepend(E e) {
+		return new ConsListImpl<>(e, this);
+	}
+
+	@Override
+	public ConsList<E> append(E e) {
+		return new ConsListImpl<>(e, this);
+	}
+
+	@Override
+	public boolean isEmpty() {
+		//Toujours vide
+		return true;
+	}
+
+	@Override
+	public E car() {
+		throw new NoSuchElementException("Liste vide");
+	}
+
+	@Override
+	public ConsList<E> cdr() {
+		return new ConsEmptyList<>();
+	}
+
+	@Override
+	public int size() {
+		//Toujours vide donc 0 element
+		return 0;
+	}
+
+	@Override
+	public <T> ConsList<T> map(Function<E, T> f) {
+		return new ConsEmptyList<>();
+	}
+	
+	@Override
+	public String toString() {
+		return "()";
+	}
+	
+	@Override
+	public int hashCode() {
+		return 0;
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		return (obj instanceof ConsEmptyList<?>);
+	}
+
+}

+ 109 - 0
TDD2019IMPL/src/migl/util/ConsList.java

@@ -0,0 +1,109 @@
+package migl.util;
+
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+
+/**
+ * Implementation of a list using the {@link migl.util.Cons} data structure.
+ * 
+ * The implementation of ConsList must be immutable, i.e. each call to the
+ * {@link #append(Object)} or {@link #prepend(Object)} methods must return a new
+ * list without changing the state of the current list. This is unlike the
+ * default behavior of {@link java.util.List} behavior.
+ * 
+ * @author leberre
+ *
+ * @param <E>
+ *            the type of the elements in the list
+ */
+public interface ConsList<E> extends Iterable<E> {
+
+    /**
+     * Insert a new element e in front of the list.
+     * 
+     * @param e
+     *            an element.
+     * @return a new list containing e in front of the current one.
+     */
+    ConsList<E> prepend(E e);
+
+    /**
+     * Insert a new element e at the end of the list
+     * 
+     * @param e
+     *            an element
+     * @return a new list containing e at the end of the current one.
+     */
+    ConsList<E> append(E e);
+
+    /**
+     * Check if the list is empty or not.
+     * 
+     * @return true if the list is empty, else false.
+     */
+    boolean isEmpty();
+
+    /**
+     * Retrieve the first element of the list.
+     * 
+     * @return the first element of the list.
+     */
+    E car();
+
+    /**
+     * Return the sublist corresponding to all but the first element.
+     * 
+     * @return all but the first element of the list.
+     */
+    ConsList<E> cdr();
+
+    /**
+     * Returns the size of the list (the number of elements it contains).
+     * 
+     * @return the number of elements in the list.
+     */
+    int size();
+
+    /**
+     * Create a new list by applying a function to each element of the list.
+     * 
+     * @param f
+     *            a function
+     * @return a list where each element is the result of applying f to an element
+     *         of the original list.
+     */
+    <T> ConsList<T> map(Function<E, T> f);
+
+    /**
+     * Performs a reduction on the elements of this list, using the provided
+     * identity value and an associative accumulation function, and returns the
+     * reduced value.
+     * 
+     * @param identity
+     *            the identity value for the accumulating function
+     * @param accumulator
+     *            an associative, stateless function for combining two values
+     * @return the result of the reduction
+     */
+    default E reduce(E identity, BinaryOperator<E> accumulator) {
+        E result = identity;
+        for (E element : this) {
+            result = accumulator.apply(result, element);
+        }
+        return result;
+    }
+
+    /**
+     * Translates the ConsList as an array of Object. The type of the
+     * 
+     * @return all the elements of the list in an array of objects
+     */
+    default Object[] toArray() {
+        Object[] array = new Object[size()];
+        int i = 0;
+        for (Object o : this) {
+            array[i++] = o;
+        }
+        return array;
+    }
+}

+ 65 - 0
TDD2019IMPL/src/migl/util/ConsListFactory.java

@@ -0,0 +1,65 @@
+package migl.util;
+
+/**
+ * Factory to create new lists.
+ * 
+ * The methods take advantage of type inference to simplify the use of the
+ * methods in the user code.
+ * 
+ * The body of the methods must be completed by the students.
+ * 
+ * @author leberre
+ *
+ */
+public final class ConsListFactory {
+
+	private ConsListFactory() {
+		// do nothing
+	}
+
+	/**
+	 * Create a new empty list.
+	 * 
+	 * @return an empty list
+	 */
+	public static <T> ConsList<T> nil() {
+		return new ConsEmptyList<T>();
+	}
+
+	/**
+	 * Create a new list containing a single element
+	 * 
+	 * @param t
+	 *            an object
+	 * @return a list containing only t
+	 */
+	public static <T> ConsList<T> singleton(T t) {
+		return new ConsListImpl<T>(t, new ConsEmptyList<>());
+	}
+
+	/**
+	 * Create a new list containing the elements given in parameter
+	 * 
+	 * @param ts
+	 *            a variable number of elements
+	 * @return a list containing those elements
+	 */
+	@SafeVarargs
+	public static <T> ConsList<T> asList(T... ts) {
+		//Si liste vide
+		if(ts.length == 0) {
+			return nil();
+		} 
+		//Si 1 element
+		else if(ts.length == 1) {
+			return singleton(ts[0]);
+		}
+		//Si +sieurs elements
+		ConsList<T> list = new ConsListImpl<>(ts[ts.length - 1], new ConsEmptyList<>());
+		for(int i = ts.length - 2; i > -1; i--) {
+			list = list.prepend(ts[i]);
+		}
+		return list;
+	}
+	
+}

+ 109 - 0
TDD2019IMPL/src/migl/util/ConsListImpl.java

@@ -0,0 +1,109 @@
+package migl.util;
+
+import java.util.Iterator;
+import java.util.function.Function;
+
+public class ConsListImpl<E> extends Cons<E, ConsList<E>> implements ConsList<E>{
+	
+	private final int size;
+
+	public ConsListImpl(E left, ConsList<E> right) {
+		super(left, right);
+		if(right == null) {
+			throw new IllegalArgumentException();
+		}
+		this.size = 1 + right.size();
+	}
+
+	@Override
+	public Iterator<E> iterator() {
+		return new Iterator<E>() {
+			private ConsList<E> current = ConsListImpl.this;
+			@Override
+			public boolean hasNext() {
+				return !current.isEmpty();
+			}
+			
+			@Override
+			public E next() {
+				E e = current.car();
+				current = current.cdr();
+				return e;
+			}
+		};
+	}
+
+	@Override
+	public ConsList<E> prepend(E e) {
+		return new ConsListImpl<>(e, this);
+	}
+
+	@Override
+	public ConsList<E> append(E e) {
+		return appendRec(e, this);
+	}
+	
+	private ConsList<E> appendRec(E e, ConsList<E> list) {
+		if(list.isEmpty()) {
+			return new ConsListImpl<>(e, list);
+		}
+		return new ConsListImpl<>(list.car(), this.appendRec(e, list.cdr()));
+	}
+
+	@Override
+	public boolean isEmpty() {
+		//Jamais vide sinon on utilise ConsEmptyList
+		return false;
+	}
+
+	@Override
+	public E car() {
+		return this.left();
+	}
+
+	@Override
+	public ConsList<E> cdr() {
+		return this.right();
+	}
+
+	@Override
+	public int size() {
+		return this.size;
+	}
+
+	@Override
+	public <T> ConsList<T> map(Function<E, T> f) {
+		ConsList<T> result = new ConsEmptyList<>();
+		for(E e : this) {
+			result = result.append(f.apply(e));
+		}
+		return result;
+	}
+	
+	@Override
+	public String toString() {
+		StringBuilder str = new StringBuilder("(");
+		for(E e : this) {
+			if(e == null) {
+				str.append("null ");
+			} else {
+				str.append(e + " ");
+			}
+		}
+		return str.toString().trim() + ")";
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+        int result = super.hashCode();
+        return prime * result + this.size;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		//Equals de cons suffisant
+		return super.equals(obj);
+	}
+	
+}

+ 8 - 0
TDD2019OWNTESTS/.classpath

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/TDD2019IMPL"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

+ 1 - 0
TDD2019OWNTESTS/.gitignore

@@ -0,0 +1 @@
+bin

+ 17 - 0
TDD2019OWNTESTS/.project

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>TDD2019OWNTESTS</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

+ 11 - 0
TDD2019OWNTESTS/.settings/org.eclipse.jdt.core.prefs

@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8

+ 10 - 0
TDD2019OWNTESTS/README.md

@@ -0,0 +1,10 @@
+# Tests unitaires et d'acceptance supplémentaires
+
+Ces tests seront utilisés pour votre projet seulement, pour compléter
+les tests publics et les tests cachés, pour augmenter la couverture
+de votre code par les tests.
+
+Pour ajouter des tests spécifiques à votre projet, vous devez simplement
+"forker" ce projet.
+
+Il vous suffit ensuite de rajouter des fichiers de tests à ce projet.

+ 0 - 0
TDD2019OWNTESTS/src/.gitkeep


+ 56 - 0
TDD2019OWNTESTS/src/migl/lisp/LispBooleanOwnTest.java

@@ -0,0 +1,56 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+public class LispBooleanOwnTest {
+	
+	@Test
+	public void testLispBooleanValue(){
+		assertTrue(LispBoolean.TRUE.value());
+		assertFalse(LispBoolean.FALSE.value());
+	}
+	
+	@Test
+	public void testLispBooleanToString() {
+		assertEquals("#t", LispBoolean.TRUE.toString());
+		assertEquals("#f", LispBoolean.FALSE.toString());
+	}
+	
+	@Test
+	public void testLispBooleanValueOfBoolean() {
+		assertEquals(LispBoolean.TRUE, LispBoolean.valueOf(true));
+		assertEquals(LispBoolean.FALSE, LispBoolean.valueOf(false));
+	}
+	
+	@Test
+	public void testLispBooleanHashCode() {
+		assertEquals(new Boolean(true).hashCode(), LispBoolean.TRUE.hashCode());
+		assertEquals(new Boolean(false).hashCode(), LispBoolean.FALSE.hashCode());
+		Map<LispBoolean, String> map = new HashMap<>();
+		map.put(LispBoolean.TRUE, "#t");
+		map.put(LispBoolean.FALSE, "#f");
+		assertEquals("#t", map.get(LispBoolean.TRUE));
+		assertEquals("#f", map.get(LispBoolean.FALSE));
+	}
+	
+	@Test
+	public void testLisbBooleanEquals() {
+		assertTrue(LispBoolean.TRUE.equals(LispBoolean.TRUE));
+		assertFalse(LispBoolean.TRUE.equals(LispBoolean.FALSE));
+		assertTrue(LispBoolean.FALSE.equals(LispBoolean.FALSE));
+		assertTrue(LispBoolean.TRUE.equals(LispBoolean.valueOf(true)));
+		assertTrue(LispBoolean.FALSE.equals(LispBoolean.valueOf(false)));
+		assertTrue(LispBoolean.TRUE.equals(LispBoolean.valueOf("#t")));
+		assertTrue(LispBoolean.FALSE.equals(LispBoolean.valueOf("#f")));
+		assertFalse(LispBoolean.TRUE.equals(true));
+		assertFalse(LispBoolean.FALSE.equals(false));
+	}
+
+}

+ 245 - 0
TDD2019OWNTESTS/src/migl/lisp/LispElementOwnTest.java

@@ -0,0 +1,245 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigInteger;
+import java.util.Map;
+import java.util.HashMap;
+
+import org.junit.Test;
+
+import migl.util.Cons;
+
+public class LispElementOwnTest {
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testGenerateBadElement() {
+		Object obj = new Object();
+		LispElement.generate(obj);
+	}
+	
+	@Test(expected = IllegalStateException.class)
+	public void testToIntFail() {
+		LispElement elt = LispElement.valueOf("5.8");
+		elt.toInt();
+	}
+	
+	@Test(expected = IllegalStateException.class)
+	public void testToNumberFail() {
+		LispElement elt = LispElement.valueOf("test");
+		elt.toNumber();
+	}
+	
+	@Test(expected = IllegalStateException.class)
+	public void testToBooleanFail() {
+		LispElement elt = LispElement.valueOf("5.8");
+		elt.toBoolean();
+	}
+	
+	@Test(expected = IllegalStateException.class)
+	public void testToStrFail() {
+		LispElement elt = LispElement.valueOf("5.8");
+		elt.toStr();
+	}
+	
+	@Test(expected = IllegalStateException.class)
+	public void testToListFail() {
+		LispElement elt = LispElement.valueOf("5.8");
+		elt.toList();
+	}
+	
+	@Test(expected = IllegalStateException.class)
+	public void testToConsFail() {
+		LispElement elt = LispElement.valueOf("5.8");
+		elt.toCons();
+	}
+	
+	@Test
+	public void testToInt() {
+		LispElement elt = LispElement.valueOf("8888888888888888");
+		BigInteger expected = new BigInteger("8888888888888888");
+		assertEquals(expected, elt.toInt());
+	}
+	
+	@Test
+	public void testToNumberFromDouble() {
+		LispElement elt = LispElement.valueOf("5.8");
+		Double expected = Double.valueOf(5.8);
+		Double value = elt.toNumber();
+		assertEquals(expected, value);
+	}
+	
+	@Test
+	public void testToNumberFromInt() {
+		LispElement elt = LispElement.valueOf("8");
+		Double expected = Double.valueOf(8.0);
+		Integer notExpected = 8;
+		assertEquals(expected, (Double) elt.toNumber());
+		assertNotEquals(notExpected, elt.toNumber());
+	}
+	
+	@Test
+	public void testToBoolean() {
+		LispElement elt1 = LispElement.valueOf("#t");
+		LispElement elt2 = LispElement.generate(false);
+		assertTrue(elt1.toBoolean());
+		assertFalse(elt2.toBoolean());
+	}
+	
+	@Test
+	public void testToStr() {
+		LispElement elt1 = LispElement.valueOf("test");
+		LispElement elt2 = LispElement.valueOf("test ");
+		assertEquals("test", elt1.toStr());
+		assertNotEquals("test", elt2.toStr());
+	}
+	
+	@Test
+	public void testToList() {
+		LispList list = LispList.valueOf("(1 2 4 8)");
+		LispElement elt = LispElement.generate(list);
+		assertEquals(LispList.valueOf("(1 2 4 8)"), elt.toList());
+		assertNotEquals(LispList.nil(), elt.toList());
+	}
+	
+	@Test
+	public void testToCons() {
+		Cons<Integer, Integer> cons = new Cons<>(8, 4);
+		LispElement elt = LispElement.generate(cons);
+		assertEquals(new Cons<Integer, Integer>(8, 4), elt.toCons());
+		assertNotEquals(new Cons<String, String>("8", "4"), elt.toCons());
+	}
+	
+	@Test
+	public void testHashCode() {
+		LispElement elt1 = LispElement.valueOf("test");
+		LispElement elt2 = LispElement.valueOf("#t");
+		LispElement elt3 = LispElement.valueOf("8");
+		LispElement elt4 = LispElement.valueOf("8.0");
+		Map<LispElement, String> map = new HashMap<>();
+		map.put(elt1, "elt1");
+		map.put(elt2, "elt2");
+		map.put(elt3, "elt3");
+		map.put(elt4, "elt4");
+		assertEquals("elt1", map.get(elt1));
+		assertEquals("elt2", map.get(elt2));
+		assertEquals("elt3", map.get(elt3));
+		assertEquals("elt4", map.get(elt4));
+	}
+	
+	@Test
+	public void testEquals() {
+		LispElement elt1 = LispElement.valueOf("test");
+		LispElement elt2 = LispElement.valueOf("test");
+		LispElement elt3 = LispElement.valueOf("Test");
+		LispElement elt4 = LispElement.valueOf("#t");
+		LispElement elt5 = LispElement.valueOf("#t");
+		LispElement elt6 = LispElement.valueOf("#f");
+		LispElement elt7 = LispElement.valueOf("8");
+		LispElement elt8 = LispElement.valueOf("8.0");
+		Object other = new Object();
+		assertTrue(elt1.equals(elt2));
+		assertFalse(elt1.equals(elt3));
+		assertTrue(elt1.equals(elt1));
+		assertFalse(elt1.equals(null));
+		assertFalse(elt1.equals(elt4));
+		assertTrue(elt4.equals(elt5));
+		assertFalse(elt4.equals(elt6));
+		assertFalse(elt7.equals(elt8));
+		assertFalse(elt1.equals(other));
+		assertEquals(elt1.hashCode(), elt2.hashCode());
+		assertNotEquals(elt1.hashCode(), elt3.hashCode());
+		assertEquals(elt4.hashCode(), elt5.hashCode());
+		assertNotEquals(elt4.hashCode(), elt6.hashCode());
+		assertNotEquals(elt7.hashCode(), elt8.hashCode());
+	}
+
+	@Test
+	public void testGenerateBigIntFromInt() {
+		LispElement elt = LispElement.generate(Integer.valueOf(8));
+		BigInteger expected = new BigInteger("8");
+		assertEquals(expected, elt.getValue());
+	}
+	
+	@Test
+	public void testGenerateBigIntFromLong() {
+		Long l = 8L;
+		BigInteger expected = new BigInteger("8");
+		assertEquals(expected, LispElement.generate(l).getValue());
+	}
+	
+	@Test
+	public void testGenerateNull() {
+		assertNull(LispElement.generate(null).getValue());
+	}
+	
+	@Test
+	public void testIsType() {
+		LispElement entier = LispElement.generate(8);
+		LispElement nombre = LispElement.generate(4.2);
+		LispElement bool = LispElement.generate(true);
+		LispElement str = LispElement.generate("str");
+		LispElement list = LispElement.generate(LispList.nil());
+		LispElement cons = LispElement.generate(new Cons<Integer, Integer>(8, 4));
+		//Entier
+		assertTrue(entier.isInt());
+		assertFalse(nombre.isInt());
+		assertFalse(bool.isInt());
+		assertFalse(str.isInt());
+		assertFalse(list.isInt());
+		assertFalse(cons.isInt());
+		//Nombre
+		assertTrue(entier.isNumber());
+		assertTrue(nombre.isNumber());
+		assertFalse(bool.isNumber());
+		assertFalse(str.isNumber());
+		assertFalse(list.isNumber());
+		assertFalse(cons.isNumber());
+		//Boolean
+		assertFalse(entier.isBoolean());
+		assertFalse(nombre.isBoolean());
+		assertTrue(bool.isBoolean());
+		assertFalse(str.isBoolean());
+		assertFalse(list.isBoolean());
+		assertFalse(cons.isBoolean());
+		//String
+		assertFalse(entier.isStr());
+		assertFalse(nombre.isStr());
+		assertFalse(bool.isStr());
+		assertTrue(str.isStr());
+		assertFalse(list.isStr());
+		assertFalse(cons.isStr());
+		//List
+		assertFalse(entier.isList());
+		assertFalse(nombre.isList());
+		assertFalse(bool.isList());
+		assertFalse(str.isList());
+		assertTrue(list.isList());
+		assertFalse(cons.isList());
+		//Cons
+		assertFalse(entier.isCons());
+		assertFalse(nombre.isCons());
+		assertFalse(bool.isCons());
+		assertFalse(str.isCons());
+		assertFalse(list.isCons());
+		assertTrue(cons.isCons());
+	}
+	
+	@Test
+	public void testCacheSize() {
+		LispElement.clear();
+		assertEquals(0, LispElement.getCacheSize());
+		LispElement.generate(8.4);
+		LispElement.generate("str");
+		LispElement.generate(true);
+		LispElement.generate(new Cons<Integer, Integer>(8, 4));
+		LispElement.generate(8.4);
+		assertEquals(4, LispElement.getCacheSize());
+		LispElement.clear();
+		assertEquals(0, LispElement.getCacheSize());
+	}
+}

+ 39 - 0
TDD2019OWNTESTS/src/migl/lisp/LispErrorTest.java

@@ -0,0 +1,39 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class LispErrorTest {
+
+	@Test
+	public void testLispErrorMessageCause() {
+		Throwable cause = new IllegalArgumentException();
+		try {
+			throw new LispError("Erreur test", cause);
+		} catch (LispError ex) {
+			assertEquals("Erreur test", ex.getMessage());
+			assertEquals(cause, ex.getCause());
+		}
+	}
+	
+	@Test
+	public void testLispErrorMessage() {
+		try {
+			throw new LispError("Erreur test");
+		} catch (LispError ex) {
+			assertEquals("Erreur test", ex.getMessage());
+		}
+	}
+	
+	@Test
+	public void testLispErrorCause() {
+		Throwable cause = new IllegalArgumentException();
+		try {
+			throw new LispError(cause);
+		} catch (LispError ex) {
+			assertEquals(cause, ex.getCause());
+		}
+	}
+	
+}

+ 307 - 0
TDD2019OWNTESTS/src/migl/lisp/LispEvalOwnTest.java

@@ -0,0 +1,307 @@
+package migl.lisp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import migl.util.ConsList;
+import migl.util.ConsListFactory;
+
+public class LispEvalOwnTest {
+	
+	private LispImpl interpreter;
+	private LispEval eval;
+
+	@Before
+	public void init() {
+		interpreter = (LispImpl) LispFactory.makeIntepreter();
+		eval = interpreter.getEval();
+	}
+	
+	@Test
+	public void testConstructWithNull() throws LispError {
+		assertNull(eval.evaluate());
+	}
+	
+	@Test(expected = IllegalArgumentException.class)
+	public void testSetLispWithNull() throws LispError {
+		eval.setLisp(null);
+	}
+	
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentQuote() throws LispError {
+		eval.setLisp(interpreter.parse("(quote #t #f"));
+		eval.evaluate();
+	}
+	
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentNot() throws LispError {
+		eval.setLisp(interpreter.parse("(not #t #f"));
+		eval.evaluate();
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentSup() throws LispError {
+		eval.setLisp(interpreter.parse("(> #t)"));
+		eval.evaluate();
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentSupEqu() throws LispError {
+		eval.setLisp(interpreter.parse("(>= #f)"));
+		eval.evaluate();
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentInf() throws LispError {
+		eval.setLisp(interpreter.parse("(< #t)"));
+		eval.evaluate();
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentInfEqu() throws LispError {
+		eval.setLisp(interpreter.parse("(<= #f)"));
+		eval.evaluate();
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentEqu() throws LispError {
+		eval.setLisp(interpreter.parse("(= #t)"));
+		eval.evaluate();
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentSubstract1() throws LispError {
+		eval.setLisp(interpreter.parse("(- 8 5 4)"));
+		eval.evaluate();
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentSubstract2() throws LispError {
+		eval.setLisp(interpreter.parse("(-)"));
+		eval.evaluate();
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentDivide1() throws LispError {
+		eval.setLisp(interpreter.parse("(/ 8)"));
+		eval.evaluate();
+	}
+
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentDivide2() throws LispError {
+		eval.setLisp(interpreter.parse("(/)"));
+		eval.evaluate();
+	}
+	
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentDivide3() throws LispError {
+		eval.setLisp(interpreter.parse("(/ 8 5 4)"));
+		eval.evaluate();
+	}
+	
+	@Test(expected = LispError.class)
+	public void testDivideByZero() throws LispError {
+		eval.setLisp(interpreter.parse("(/ 8 0)"));
+		eval.evaluate();
+	}
+	
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentAbs() throws LispError {
+		eval.setLisp(interpreter.parse("(abs 8 8)"));
+		eval.evaluate();
+	}
+	
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentPow() throws LispError {
+		eval.setLisp(interpreter.parse("(pow 8)"));
+		eval.evaluate();
+	}
+	
+	@Test(expected = LispError.class)
+	public void testIncorrectNumberArgumentMap() throws LispError {
+		eval.setLisp(interpreter.parse("(map 8)"));
+		eval.evaluate();
+	}
+	
+	@Test(expected = LispError.class)
+	public void testMapException1() throws LispError {
+		eval.setLisp(interpreter.parse("(map 8 4)"));
+		eval.evaluate();
+	}
+	
+	@Test(expected = LispError.class)
+	public void testMapException2() throws LispError {
+		eval.setLisp(interpreter.parse("(define f (lambda (x) (- x x)))"));
+		eval.evaluate();
+		eval.setLisp(interpreter.parse("(map f 8)"));
+		eval.evaluate();
+	}
+	
+	/* --- */
+	
+	@Test
+	public void testEvaluateSingleton() throws LispError {
+		eval.setLisp(interpreter.parse("8"));
+		assertEquals(LispElement.generate(8), eval.evaluate());
+	}
+	
+	@Test(expected = LispError.class)
+	public void testUnknowOperator() throws LispError {
+		eval.setLisp(interpreter.parse("(gl2 #t)"));
+		eval.evaluate();
+	}
+	
+	@Test(expected = LispError.class)
+	public void testMalformedList() throws LispError {
+		ConsList<Object> list = ConsListFactory.nil();
+		list = list.prepend(new Object()).prepend("not");
+		eval.setLisp(list);
+		eval.evaluate();
+	}
+	
+	@Test
+	public void testOriginMalformedListException() {
+		ConsList<Object> list = ConsListFactory.nil();
+		list = list.prepend(new Object()).prepend("not");
+		try {
+			eval.setLisp(list);
+			eval.evaluate();
+			fail("No exception thrown");
+		} catch (LispError ex) {
+			assertTrue(ex.getCause() instanceof IllegalArgumentException);
+		}
+	}
+	
+	@Test
+	public void testOriginBadArgumentTypeException() {
+		try {
+			eval.setLisp(interpreter.parse("(not 8)"));
+			eval.evaluate();
+			fail("No exception thrown");
+		} catch (LispError ex) {
+			assertTrue(ex.getCause() instanceof IllegalStateException);
+		}
+	}
+	
+	@Test(expected = LispError.class)
+	public void testEvaluateIncorrectObject() throws LispError {
+		eval.setLisp(interpreter);
+		eval.evaluate();
+	}
+	
+	@Test
+	public void testSubList() throws LispError {
+		eval.setLisp(interpreter.parse("(+ (- 8 4.2) (* 2 3))"));
+		assertEquals(LispElement.generate(9.8), eval.evaluate());
+	}
+	
+	@Test(expected = LispError.class)
+	public void testForbiddenName1() throws LispError {
+		eval.verifyForbiddenName("#t");
+	}
+	
+	@Test(expected = LispError.class)
+	public void testForbiddenName2() throws LispError {
+		eval.verifyForbiddenName("8");
+	}
+	
+	@Test(expected = LispError.class)
+	public void testForbiddenName3() throws LispError {
+		eval.verifyForbiddenName("8.4");
+	}
+	
+	@Test(expected = LispError.class)
+	public void testForbiddenName4() throws LispError {
+		eval.verifyForbiddenName("+");
+	}
+	
+	@Test
+	public void testForbiddenName5() throws LispError {
+		eval.verifyForbiddenName("var");
+	}
+	
+	@Test
+	public void testEvaluateList() throws LispError {
+		ConsList<Object> cl = ConsListFactory.nil();
+		cl = cl.prepend(8).prepend(4).prepend("+");
+		assertEquals(LispElement.generate(12), eval.evaluateList(cl));
+	}
+	
+	@Test
+	public void testEvaluateListLambda() throws LispError {
+		LispParser parser = new LispParser("(define fonction (lambda (x) (+ x 2)))");
+		eval.setLisp(parser.parse());
+		eval.evaluate();
+		ConsList<Object> cl = ConsListFactory.nil();
+		cl = cl.prepend(8).prepend("fonction");
+		assertEquals(LispElement.generate(10), eval.evaluateList(cl));
+	}
+	
+	@Test(expected = LispError.class)
+	public void testEvaluateListError() throws LispError {
+		ConsList<Object> cl = ConsListFactory.nil();
+		cl = cl.prepend(8).prepend("undef");
+		assertEquals(LispElement.generate(10), eval.evaluateList(cl));
+	}
+	
+	@Test
+	public void testVarNameGetElement() throws LispError {
+		LispParser parser = new LispParser("(define . 8)");
+		eval.setLisp(parser.parse());
+		eval.evaluate();
+		assertEquals(LispElement.generate("-"), eval.getElement("-"));
+		assertEquals(LispElement.generate(8), eval.getElement("."));
+	}
+	
+	@Test
+	public void testOperators() throws LispError {
+		assertEquals(LispElement.generate(true), interpreter.eval("(not #f)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(not #t)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(and #t #t)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(and #f #t)"));
+		assertEquals(LispElement.generate(true), interpreter.eval("(or #f #t)"));
+		assertEquals(LispElement.generate(false), interpreter.eval("(or #f #f)"));
+		assertEquals(LispElement.generate(4.2), interpreter.eval("(if #f 8 4.2)"));
+		assertEquals(LispElement.generate(8), interpreter.eval("(if #t 8 4.2)"));
+		assertEquals(LispElement.generate(8), interpreter.eval("(+ 5 3)"));
+		assertEquals(LispElement.generate(8.4), interpreter.eval("(+ 5 3.4)"));
+		assertEquals(LispElement.generate(8.8), interpreter.eval("(+ 4.4 4.4)"));
+		assertEquals(LispElement.generate(8.0), interpreter.eval("(+ 4 4 0.0)"));
+		assertEquals(LispElement.generate(16), interpreter.eval("(* 4 2 2)"));
+		assertEquals(LispElement.generate(8.0), interpreter.eval("(* 4.0 2)"));
+		assertEquals(LispElement.generate(10.0), interpreter.eval("(* 2.0 5.0)"));
+		assertEquals(LispElement.generate(-8), interpreter.eval("(- 8)"));
+		assertEquals(LispElement.generate(-8.4), interpreter.eval("(- 8.4)"));
+		assertEquals(LispElement.generate(8), interpreter.eval("(- 16 8)"));
+		assertEquals(LispElement.generate(10.0), interpreter.eval("(- 18.0 8)"));
+		assertEquals(LispElement.generate(2.0), interpreter.eval("(- 10.0 8.0)"));
+		assertEquals(LispElement.generate(-11), interpreter.eval("(- 9 (* 4 5))"));
+		assertEquals(LispElement.generate(2), interpreter.eval("(/ 8 4)"));
+		assertEquals(LispElement.generate(4.0), interpreter.eval("(/ 12 3.0)"));
+		assertEquals(LispElement.generate(10.0), interpreter.eval("(/ 80.0 8.0)"));
+		assertEquals(LispElement.generate("(+ 8 4)"), interpreter.eval("(quote (+ 8 4))"));
+		assertEquals(LispElement.generate(8), interpreter.eval("(abs 8)"));
+		assertEquals(LispElement.generate(8), interpreter.eval("(abs -8)"));
+		assertEquals(LispElement.generate(8.4), interpreter.eval("(abs 8.4)"));
+		assertEquals(LispElement.generate(8.4), interpreter.eval("(abs -8.4)"));
+		assertEquals(LispElement.generate(8.4), interpreter.eval("(abs (- 8.4))"));
+		assertEquals(LispElement.generate(8.0), interpreter.eval("(pow 2 3)"));
+		assertEquals(LispElement.generate(8.0), interpreter.eval("(pow 2.0 3)"));
+		assertEquals(LispElement.generate(8.0), interpreter.eval("(pow 2 3.0)"));
+		assertEquals(LispElement.generate(8.0), interpreter.eval("(pow 2.0 3.0)"));
+	}
+	
+	@Test
+	public void testMapOperator() throws LispError {
+		interpreter.eval("(define g (lambda (x) (+ x x)))");
+		assertEquals(LispElement.generate(LispList.nil()), interpreter.eval("(map g (- 8 0))"));
+		interpreter.eval("(define h (lambda (x y) (list x y)))");
+		assertEquals(LispList.valueOf("(8 16)").toString(), interpreter.eval("(map g (h 4 8))").toString());
+	}
+
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно