From 266ddec80a58ef9f377fb7009a0b7a28b235eec9 Mon Sep 17 00:00:00 2001
From: sebastien Curt <curt.sebastien@gmail.com>
Date: Thu, 7 Jan 2021 14:03:13 +0100
Subject: [PATCH] Add #17 unit tests Add GraphExportException for
 GraphExporter.write

---
 .../Convert/ExportUnlDocumentsHandler.java    |   5 +-
 .../fr/tetras_libre/unltools/unl/Graph.java   |  13 +-
 .../unltools/unl/GraphExportException.java    |   7 +
 .../unltools/unl/GraphExporter.java           |   2 +-
 .../unltools/unl/NoEntryNodeException.java    |   9 +-
 .../exporters/dot/DotFileGraphExporter.java   |  14 +-
 .../AbstractFlyweightUnlArgumentProvider.java |   4 +
 .../unl/AbstractUnlArgumentProvider.java      |  11 +
 .../fr/tetras_libre/unltools/unl/AllUnl.java  |   5 +
 .../fr/tetras_libre/unltools/unl/CatsUnl.java |   5 +
 .../tetras_libre/unltools/unl/Issue13Unl.java |   4 +
 .../tetras_libre/unltools/unl/Issue17Unl.java | 334 ++++++++++++++++++
 .../fr/tetras_libre/unltools/unl/R1Unl.java   |   4 +
 .../fr/tetras_libre/unltools/unl/R2Unl.java   |   4 +
 .../unltools/unl/UnlSentences.java            |  26 ++
 .../unl/exporters/dot/DotFileBuilderTest.java |  43 ++-
 ...ntenceWithExpectedUnlDocumentsChecker.java |  10 +
 .../unltools/unl/parser/UnlParserTest.java    |  57 ++-
 .../unltools/unl/parser/WrapperUnlParser.java |   6 +-
 .../src/main/java/unl2rdf/Unl2Rdf.java        |   4 +-
 20 files changed, 524 insertions(+), 43 deletions(-)
 create mode 100644 unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/GraphExportException.java
 create mode 100644 unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/Issue17Unl.java
 create mode 100644 unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/Issue17SentenceWithExpectedUnlDocumentsChecker.java

diff --git a/unl-tools-application/src/main/java/fr/tetras_libre/unltools/Convert/ExportUnlDocumentsHandler.java b/unl-tools-application/src/main/java/fr/tetras_libre/unltools/Convert/ExportUnlDocumentsHandler.java
index 62ed343..5edc94a 100644
--- a/unl-tools-application/src/main/java/fr/tetras_libre/unltools/Convert/ExportUnlDocumentsHandler.java
+++ b/unl-tools-application/src/main/java/fr/tetras_libre/unltools/Convert/ExportUnlDocumentsHandler.java
@@ -2,6 +2,7 @@ package fr.tetras_libre.unltools.Convert;
 
 import fr.tetras_libre.unltools.cqrs.CommandHandler;
 import fr.tetras_libre.unltools.cqrs.Result;
+import fr.tetras_libre.unltools.unl.GraphExportException;
 import fr.tetras_libre.unltools.unl.GraphExporterFactory;
 
 import java.io.IOException;
@@ -18,8 +19,8 @@ public class ExportUnlDocumentsHandler implements CommandHandler<ExportUnlDocume
         try {
             var graphExporter = factory.createGraphExporter(command.getWriter(), command.getExporterName());
             graphExporter.write(command.getGraphImporter().Import());
-        } catch (IOException e) {
-            return Result.Failure(String.format("Cannot export unl documents to format '%s'", command.getExporterName()),
+        } catch (IOException | GraphExportException e) {
+            return Result.Failure(String.format("Cannot export unl documents to format '%s' (reason: '%s')", command.getExporterName(), e.getMessage()),
                     e);
         }
         return Result.Success();
diff --git a/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/Graph.java b/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/Graph.java
index 33197d0..ee6dace 100644
--- a/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/Graph.java
+++ b/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/Graph.java
@@ -92,12 +92,21 @@ public class Graph {
         }
 
         if (null == graphNode) {
-            throw new NoEntryNodeException("No Entry node for subgraph " + graphNumber);
+            throw new NoEntryNodeException("No Entry node for subgraph " + graphNumber, graphNumber);
         }
         return graphNode;
-
     }
 
+//    public GraphNode getNodesWithinSubgraph(String graphNumber){
+//        if (null == graphNumber) throw new IllegalArgumentException("GraphNumber cannot be null");
+//
+//        var result = this.relations.stream().filter(e -> graphNumber.equals(e.getSubGraphReferenceLabel())).findFirst().get();
+//        if (null != result.getNode1()) return result.getNode1();
+//        if (null != result.getNode2()) return result.getNode2();
+//
+//        throw new RuntimeException(String.format("Cannot find any graph node within '%s' subgraph", graphNumber));
+//    }
+
     @Override
     public java.lang.String toString() {
         return InternalToString();
diff --git a/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/GraphExportException.java b/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/GraphExportException.java
new file mode 100644
index 0000000..dfafe26
--- /dev/null
+++ b/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/GraphExportException.java
@@ -0,0 +1,7 @@
+package fr.tetras_libre.unltools.unl;
+
+public class GraphExportException extends Exception {
+    public GraphExportException(String errorMessage, Throwable exception){
+        super(errorMessage, exception);
+    }
+}
diff --git a/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/GraphExporter.java b/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/GraphExporter.java
index a61a61b..4507799 100644
--- a/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/GraphExporter.java
+++ b/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/GraphExporter.java
@@ -4,5 +4,5 @@ import java.io.IOException;
 import java.util.List;
 
 public interface GraphExporter {
-    void write(List<UnlDocument> g) throws IOException;
+    void write(List<UnlDocument> g) throws IOException, GraphExportException;
 }
diff --git a/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/NoEntryNodeException.java b/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/NoEntryNodeException.java
index 45dbcf4..660d179 100644
--- a/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/NoEntryNodeException.java
+++ b/unl-tools-core/src/main/java/fr/tetras_libre/unltools/unl/NoEntryNodeException.java
@@ -1,7 +1,14 @@
 package fr.tetras_libre.unltools.unl;
 
 public class NoEntryNodeException extends Exception {
-    public NoEntryNodeException(String message) {
+    private final String nodeName;
+
+    public NoEntryNodeException(String message, String nodeName) {
         super(message);
+        this.nodeName = nodeName;
+    }
+
+    public String getNodeName() {
+        return nodeName;
     }
 }
diff --git a/unl-tools-infrastructure/src/main/java/fr/tetras_libre/unltools/unl/exporters/dot/DotFileGraphExporter.java b/unl-tools-infrastructure/src/main/java/fr/tetras_libre/unltools/unl/exporters/dot/DotFileGraphExporter.java
index 7710598..5811bb5 100644
--- a/unl-tools-infrastructure/src/main/java/fr/tetras_libre/unltools/unl/exporters/dot/DotFileGraphExporter.java
+++ b/unl-tools-infrastructure/src/main/java/fr/tetras_libre/unltools/unl/exporters/dot/DotFileGraphExporter.java
@@ -1,6 +1,7 @@
 package fr.tetras_libre.unltools.unl.exporters.dot;
 
 import fr.tetras_libre.unltools.unl.*;
+import fr.tetras_libre.unltools.unl.GraphExportException;
 
 import java.io.IOException;
 import java.io.Writer;
@@ -23,11 +24,11 @@ public class DotFileGraphExporter implements GraphExporter {
     }
 
 
-    private void write(Graph g) throws IOException {
+    private void write(Graph g) throws IOException, GraphExportException {
         try {
             this.InternalWrite(g);
         } catch (NoEntryNodeException e) {
-            // TODO : to define what to do here
+            throw new GraphExportException("Cannot export graph because entry node for subGraph '" + e.getNodeName() + "' not found.", e);
         }
     }
 
@@ -165,7 +166,12 @@ public class DotFileGraphExporter implements GraphExporter {
      */
     private String getTextForSubGraphRelationOrGetNodeNumber(GraphNode graphNode, Graph g) throws NoEntryNodeException {
         if (graphNode instanceof SubGraphReferenceNode) {
-            return Integer.toString(g.getEntryNode(((SubGraphReferenceNode) graphNode).getReferenceNumber()).getNodeNumber());
+//            try{
+                return Integer.toString(g.getEntryNode(((SubGraphReferenceNode) graphNode).getReferenceNumber()).getNodeNumber());
+//            }
+//            catch (NoEntryNodeException ex){
+//                return Integer.toString(g.getNodesWithinSubgraph(((SubGraphReferenceNode) graphNode).getReferenceNumber()).getNodeNumber());
+//            }
         } else {
             return Integer.toString(graphNode.getNodeNumber());
         }
@@ -190,7 +196,7 @@ public class DotFileGraphExporter implements GraphExporter {
     }
 
     @Override
-    public void write(List<UnlDocument> documents) throws IOException {
+    public void write(List<UnlDocument> documents) throws IOException, GraphExportException {
         for (var document : documents) {
             for (var documentNode : document.getDocElements()) {
                 this.write(documentNode.getGraph());
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AbstractFlyweightUnlArgumentProvider.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AbstractFlyweightUnlArgumentProvider.java
index b1569e8..0c41f2a 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AbstractFlyweightUnlArgumentProvider.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AbstractFlyweightUnlArgumentProvider.java
@@ -7,6 +7,10 @@ import java.util.List;
 public abstract class AbstractFlyweightUnlArgumentProvider extends AbstractUnlArgumentProvider implements GraphImporter {
     private static final Dictionary<Class<?>, List<UnlDocument>> values = new Hashtable<>();
 
+    public AbstractFlyweightUnlArgumentProvider(String unlSourceString) {
+        super(unlSourceString);
+    }
+
     protected abstract List<UnlDocument> buildUnlDocuments();
 
     final public List<UnlDocument> getUnlDocuments() {
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AbstractUnlArgumentProvider.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AbstractUnlArgumentProvider.java
index 8c9ac6b..7ed7d9a 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AbstractUnlArgumentProvider.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AbstractUnlArgumentProvider.java
@@ -9,8 +9,19 @@ import java.util.stream.Stream;
 
 public abstract class AbstractUnlArgumentProvider implements ArgumentsProvider {
 
+    private String unlSourceString;
+
+    protected AbstractUnlArgumentProvider(String unlSourceString) {
+        if(null == unlSourceString) throw new IllegalArgumentException("unlSourceString should not be null");
+        this.unlSourceString = unlSourceString;
+    }
+
     public abstract List<UnlDocument> getUnlDocuments();
 
+    public String getUnlStringSource() {
+        return this.unlSourceString;
+    }
+
     @Override
     public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
         return Stream.of(Arguments.of(getUnlDocuments()));
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AllUnl.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AllUnl.java
index 43274be..988ef42 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AllUnl.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/AllUnl.java
@@ -4,6 +4,11 @@ import java.util.Collections;
 import java.util.List;
 
 public class AllUnl extends AbstractFlyweightUnlArgumentProvider {
+
+    public AllUnl(){
+        super(UnlSentences.All);
+    }
+
     @Override
     protected List<UnlDocument> buildUnlDocuments() {
         var unlDocument = new UnlDocument("[D]");
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/CatsUnl.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/CatsUnl.java
index 9311784..3c8c916 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/CatsUnl.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/CatsUnl.java
@@ -6,6 +6,11 @@ import fr.tetras_libre.unltools.unl.builders.UnlDocumentNodeBuilder;
 import java.util.*;
 
 public class CatsUnl extends AbstractFlyweightUnlArgumentProvider implements GraphImporter {
+
+    public CatsUnl(){
+        super(UnlSentences.Cats);
+    }
+
     private static UnlDocumentNode CreateWithOldBuilder() {
         var graph = new Graph();
 
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/Issue13Unl.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/Issue13Unl.java
index 05c871b..4eca596 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/Issue13Unl.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/Issue13Unl.java
@@ -9,6 +9,10 @@ import java.util.List;
 public class Issue13Unl extends AbstractFlyweightUnlArgumentProvider {
     private static UnlDocument unlDocument;
 
+    public Issue13Unl() {
+        super(UnlSentences.Issue13);
+    }
+
     public static UnlDocumentNode buildSentenceNode1() {
         return UnlDocumentNodeBuilder
             .createBuilder()
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/Issue17Unl.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/Issue17Unl.java
new file mode 100644
index 0000000..0333fd9
--- /dev/null
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/Issue17Unl.java
@@ -0,0 +1,334 @@
+package fr.tetras_libre.unltools.unl;
+
+import fr.tetras_libre.unltools.unl.builders.GraphBuilder;
+import fr.tetras_libre.unltools.unl.builders.RestrictionOrientation;
+import fr.tetras_libre.unltools.unl.builders.UnlDocumentNodeBuilder;
+
+import java.util.Collections;
+import java.util.List;
+
+public class Issue17Unl extends AbstractFlyweightUnlArgumentProvider {
+
+    private static UnlDocument unlDocument;
+
+    public Issue17Unl(){
+        super(UnlSentences.Issue17);
+    }
+
+    @Override
+    protected List<UnlDocument> buildUnlDocuments() {
+        if (null == Issue17Unl.unlDocument) {
+            Issue17Unl.unlDocument = new UnlDocument();
+            Issue17Unl.unlDocument.add(buildSentenceNode());
+        }
+        return Collections.singletonList(Issue17Unl.unlDocument);
+    }
+
+    private void addGraphRelation1(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("agt")
+                        .noReference()
+                        .leftNode(n ->
+                                n.universalWord(uw ->
+                                        uw.headWord("allow")
+                                                .addSimpleRestriction("icl", RestrictionOrientation.Right, "do")
+                                                .addSimpleRestriction("equ", RestrictionOrientation.Right, "permit")
+                                                .addSimpleRestriction("agt", RestrictionOrientation.Right, "volitional_thing")
+                                                .addSimpleRestriction("obj", RestrictionOrientation.Right, "uw")
+                                                .addSimpleRestriction("ben", RestrictionOrientation.Right, "volitional_thing")
+                                )
+                                        .addAttribute(".@entry")
+                                        .addAttribute(".@present")
+                                        .addAttribute(".@promise"))
+                        .rightNode(rn -> rn.universalWord(uw -> uw.headWord("system")
+                                .addTernaryTransitiveRestriction("icl", "group", "thing", RestrictionOrientation.Right)
+                        )
+                                .addAttribute(".@def")));
+    }
+
+    private void addGraphRelation2(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("agt")
+                        .reference(":02")
+                        .leftNode(ln ->
+                                ln.universalWord(uw -> uw.headWord("adjust")
+                                        .addTernaryTransitiveRestriction("icl", "change", "do", RestrictionOrientation.Right)
+                                        .addSimpleRestriction("equ", RestrictionOrientation.Right, "correct")
+                                        .addSimpleRestriction("cob", RestrictionOrientation.Right, "thing")
+                                        .addSimpleRestriction("agt", RestrictionOrientation.Right, "volitional_thing")
+                                        .addSimpleRestriction("obj" , RestrictionOrientation.Right, "thing"))
+                                        .addAttribute(".@entry"))
+                        .rightNode(rn -> rn.universalWord(uw ->
+                                uw.headWord("operator")
+                                        .addTernaryTransitiveRestriction("icl", "function", "thing", RestrictionOrientation.Right))
+                                .instanceNumber(":01")
+                                .addAttribute(".@indef")));
+    }
+
+    private void addGraphRelation3(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("obj")
+                        .reference(":02")
+                        .leftNode(ln ->
+                                ln.universalWord(uw -> uw.headWord("adjust")
+                                        .addTernaryTransitiveRestriction("icl", "change", "do", RestrictionOrientation.Right)
+                                        .addSimpleRestriction("equ", RestrictionOrientation.Right, "correct")
+                                        .addSimpleRestriction("cob", RestrictionOrientation.Right, "thing")
+                                        .addSimpleRestriction("agt", RestrictionOrientation.Right, "volitional_thing")
+                                        .addSimpleRestriction("obj" , RestrictionOrientation.Right, "thing"))
+                                        .addAttribute(".@entry"))
+                        .rightNode(rn ->
+                                rn.universalWord(uw -> uw.headWord("brightness")
+                                        .addTernaryTransitiveRestriction("icl", "light", "thing", RestrictionOrientation.Right)
+                                        .addSimpleRestriction("ant", RestrictionOrientation.Right, "dullness"))
+                                        .addAttribute(".@def")));
+    }
+
+    private void addGraphRelation4(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("mod")
+                        .reference(":02")
+                        .leftNode(ln ->
+                                ln.universalWord(uw -> uw.headWord("touch")
+                                        .addTernaryTransitiveRestriction("icl", "contact", "thing", RestrictionOrientation.Right)
+                                ))
+                        .rightNode(rn ->
+                                rn.universalWord(uw -> uw.headWord("poc"))));
+    }
+
+    private void addGraphRelation5(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("mod")
+                        .reference(":02")
+                        .leftNode(lf ->
+                                lf.universalWord(uw ->
+                                        uw.headWord("panel")
+                                                .addTernaryTransitiveRestriction("icl", "sheet", "thing", RestrictionOrientation.Right))
+                                        .addAttribute(".@def"))
+                        .rightNode(rn ->
+                                rn.universalWord(uw ->
+                                        uw.headWord("touch")
+                                .addTernaryTransitiveRestriction("icl", "contact", "thing", RestrictionOrientation.Right))));
+    }
+
+    private void addGraphRelation6(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("obj")
+                        .reference(":02")
+                        .leftNode(ln ->
+                                ln.universalWord(uw -> uw.headWord("brightness")
+                                        .addTernaryTransitiveRestriction("icl", "light", "thing", RestrictionOrientation.Right)
+                                        .addSimpleRestriction("ant", RestrictionOrientation.Right, "dullness")
+                                )
+                                        .addAttribute(".@def"))
+                        .rightNode(rn ->
+                                rn.universalWord(uw -> uw.headWord("panel")
+                                        .addTernaryTransitiveRestriction("icl", "sheet", "thing", RestrictionOrientation.Right))
+                                        .addAttribute(".@def")));
+    }
+
+    private void addGraphRelation7(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("dur")
+                        .reference(":02")
+                        .leftNode(ln ->
+                                ln.universalWord(uw ->
+                                        uw.headWord("panel")
+                                                .addTernaryTransitiveRestriction("icl", "sheet", "thing", RestrictionOrientation.Right))
+                                        .addAttribute(".@def"))
+                        .rightNode(rn ->
+                                rn.universalWord(uw -> uw.headWord("while")
+                                        .addSimpleRestriction("icl", RestrictionOrientation.Right, "how")
+                                        .addSimpleRestriction("equ", RestrictionOrientation.Right, "whilst")
+                                        .addSimpleRestriction("tim", RestrictionOrientation.Left, "uw")
+                                        .addSimpleRestriction("obj", RestrictionOrientation.Right, "uw"))));
+    }
+
+    private void addGraphRelation8(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("man")
+                        .reference(":03")
+                        .leftNode(ln ->
+                                ln.universalWord(uw -> uw.headWord("leave")
+                                        .addTernaryTransitiveRestriction("icl", "refrain", "do", RestrictionOrientation.Right)
+                                        .addSimpleRestriction("agt", RestrictionOrientation.Right, "thing")
+                                        .addSimpleRestriction("obj", RestrictionOrientation.Right, "thing")
+                                        .addSimpleRestriction("asp", RestrictionOrientation.Right, "thing"))
+                                        .addAttribute(".@entry"))
+                        .rightNode(rn ->
+                                rn.universalWord(uw -> uw.headWord("still")
+                                        .addSimpleRestriction("icl", RestrictionOrientation.Right, "how")
+                                        .addSimpleRestriction("com", RestrictionOrientation.Right, "duration"))));
+    }
+
+    private void addGraphRelation9(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("mod")
+                        .reference(":03")
+                        .leftNode(ln ->
+                                ln.universalWord(uw -> uw.headWord("screen")
+                                        .addTernaryTransitiveRestriction("icl", "surface", "thing", RestrictionOrientation.Right))
+                                        .addAttribute(".@indef"))
+                        .rightNode(rn ->
+                                rn.universalWord(uw -> uw.headWord("operable")
+                                        .addSimpleRestriction("icl", RestrictionOrientation.Right, "adj"))));
+    }
+
+    private void addGraphRelation10(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("obj")
+                        .reference(":03")
+                        .leftNode(ln ->
+                                ln.universalWord(uw -> uw.headWord("leave")
+                                        .addTernaryTransitiveRestriction("icl", "refrain", "do", RestrictionOrientation.Right)
+                                        .addSimpleRestriction("agt", RestrictionOrientation.Right, "thing")
+                                        .addSimpleRestriction("obj", RestrictionOrientation.Right, "thing")
+                                        .addSimpleRestriction("asp", RestrictionOrientation.Right, "thing"))
+                                        .addAttribute(".@entry"))
+                        .rightNode(rn ->
+                                rn.universalWord(uw -> uw.headWord("screen")
+                                        .addTernaryTransitiveRestriction("icl", "surface", "thing", RestrictionOrientation.Right))
+                                        .addAttribute(".@indef")));
+    }
+
+    private void addGraphRelation11(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr -> gr.label("ben")
+                .reference(":03")
+                .leftNode(ln ->
+                        ln.universalWord(uw -> uw.headWord("leave")
+                                .addTernaryTransitiveRestriction("icl", "refrain", "do", RestrictionOrientation.Right)
+                                .addSimpleRestriction("agt", RestrictionOrientation.Right, "thing")
+                                .addSimpleRestriction("obj", RestrictionOrientation.Right, "thing")
+                                .addSimpleRestriction("asp", RestrictionOrientation.Right, "thing"))
+                                .addAttribute(".@entry"))
+                .rightNode(rn -> rn.universalWord(uw -> uw.headWord("operator")
+                        .addTernaryTransitiveRestriction("icl", "function", "thing", RestrictionOrientation.Right))
+                        .instanceNumber(":02")
+                        .addAttribute(".@def")));
+    }
+
+    private void addGraphRelation12(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("qua")
+                        .reference(":01")
+                        .leftNode(ln ->
+                                ln.universalWord(uw -> uw.headWord("white")
+                                        .addTernaryTransitiveRestriction("icl", "person", "thing", RestrictionOrientation.Right)))
+                        .rightNode(rn -> rn.universalWord(uw -> uw.headWord("all")
+                                .addSimpleRestriction("icl", RestrictionOrientation.Right, "quantity")
+                                .addSimpleRestriction("ant", RestrictionOrientation.Right, "some")
+                                .addSimpleRestriction("per", RestrictionOrientation.Right, "thing"))
+                                .instanceNumber(":01")));
+    }
+
+    private void addGraphRelation13(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr ->
+                gr.label("obj")
+                        .reference(":01")
+                        .leftNode(ln ->
+                                ln.universalWord(uw -> uw.headWord("neither_nor")
+                                        .addSimpleRestriction("icl", RestrictionOrientation.Right, "how")
+                                        .addSimpleRestriction("equ", RestrictionOrientation.Right, "nor")
+                                        .addSimpleRestriction("com", RestrictionOrientation.Right, "two_options")
+                                        .addSimpleRestriction("obj", RestrictionOrientation.Right, "uw")
+                                        .addSimpleRestriction("and", RestrictionOrientation.Left, "uw")))
+                        .rightNode(rn ->
+                                rn.universalWord(uw -> uw.headWord("white")
+                                        .addTernaryTransitiveRestriction("icl", "person", "thing", RestrictionOrientation.Right))));
+    }
+
+    private void addGraphRelation14(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr -> gr.label("and")
+                .reference(":01")
+                .leftNode(ln ->
+                        ln.universalWord(uw -> uw.headWord("black")
+                                .addTernaryTransitiveRestriction("icl", "achromatic_color", "thing", RestrictionOrientation.Right)
+                                .addSimpleRestriction("ant", RestrictionOrientation.Right, "white")))
+
+                .rightNode(rn -> rn.universalWord(uw -> uw.headWord("neither_nor")
+                        .addSimpleRestriction("icl", RestrictionOrientation.Right, "how")
+                        .addSimpleRestriction("equ", RestrictionOrientation.Right, "nor")
+                        .addSimpleRestriction("com", RestrictionOrientation.Right, "two_options")
+                        .addSimpleRestriction("obj", RestrictionOrientation.Right, "uw")
+                        .addSimpleRestriction("and", RestrictionOrientation.Left, "uw"))));
+    }
+
+    private void addGraphRelation15(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr -> gr.label("qua")
+                .reference(":01")
+                .leftNode(ln -> ln.universalWord(uw -> uw.headWord("black")
+                        .addTernaryTransitiveRestriction("icl", "achromatic_color", "thing", RestrictionOrientation.Right)
+                        .addSimpleRestriction("ant", RestrictionOrientation.Right, "white")))
+                .rightNode(rn -> rn.universalWord(uw -> uw.headWord("all")
+                        .addSimpleRestriction("icl", RestrictionOrientation.Right, "quantity")
+                        .addSimpleRestriction("ant", RestrictionOrientation.Right, "some")
+                        .addSimpleRestriction("per", RestrictionOrientation.Right, "thing"))
+                        .instanceNumber(":02")));
+    }
+
+    private void addGraphRelation16(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr -> gr.label("cnt")
+                .reference(":03")
+                .leftNode(ln -> ln.universalWord(uw -> uw.headWord("operator")
+                        .addTernaryTransitiveRestriction("icl", "function", "thing", RestrictionOrientation.Right))
+                        .instanceNumber(":02")
+                        .addAttribute(".@def"))
+                .rightSubGraphNode(rsgn -> rsgn.referenceNumber(":01").addAttribute(".@parenthesis")));
+    }
+
+    private void addGraphRelation17(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr -> gr.label("obj")
+                .noReference()
+                .leftNode(ln -> ln.universalWord(uw -> uw.headWord("allow")
+                        .addSimpleRestriction("icl", RestrictionOrientation.Right, "do")
+                        .addSimpleRestriction("equ", RestrictionOrientation.Right, "permit")
+                        .addSimpleRestriction("agt", RestrictionOrientation.Right, "volitional_thing")
+                        .addSimpleRestriction("obj", RestrictionOrientation.Right, "uw")
+                        .addSimpleRestriction("ben", RestrictionOrientation.Right, "volitional_thing"))
+                        .addAttribute(".@entry")
+                        .addAttribute(".@present")
+                        .addAttribute(".@promise"))
+                .rightSubGraphNode(rsgn -> rsgn.referenceNumber(":02")));
+    }
+
+    private void addGraphRelation18(GraphBuilder.IBuild gb) {
+        gb.addGraphRelation(gr -> gr.label("obj")
+                .reference(":02")
+                .leftNode(ln -> ln.universalWord(uw -> uw.headWord("while")
+                        .addSimpleRestriction("icl", RestrictionOrientation.Right, "how")
+                        .addSimpleRestriction("equ", RestrictionOrientation.Right, "whilst")
+                        .addSimpleRestriction("tim", RestrictionOrientation.Left, "uw")
+                        .addSimpleRestriction("obj", RestrictionOrientation.Right, "uw")))
+                .rightSubGraphNode(rsgn -> rsgn.referenceNumber(":03")));
+    }
+
+    private UnlDocumentNode buildSentenceNode() {
+        return UnlDocumentNodeBuilder
+                .createBuilder()
+                .withNodeType(UnlDocumentNodeType.Sentence)
+                .withLabel("[S:00]")
+                .withGraph(g ->
+                {
+                    addGraphRelation1(g);
+                    addGraphRelation2(g);
+                    addGraphRelation3(g);
+                    addGraphRelation4(g);
+                    addGraphRelation5(g);
+                    addGraphRelation6(g);
+                    addGraphRelation7(g);
+                    addGraphRelation8(g);
+                    addGraphRelation9(g);
+                    addGraphRelation10(g);
+                    addGraphRelation11(g);
+                    addGraphRelation12(g);
+                    addGraphRelation13(g);
+                    addGraphRelation14(g);
+                    addGraphRelation15(g);
+                    addGraphRelation16(g);
+                    addGraphRelation17(g);
+                    addGraphRelation18(g);
+                    return g;
+                })
+                .buildUnlDocumentNode();
+    }
+}
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/R1Unl.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/R1Unl.java
index 8d8af44..85b8888 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/R1Unl.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/R1Unl.java
@@ -7,6 +7,10 @@ import java.util.TreeSet;
 
 public class R1Unl extends AbstractFlyweightUnlArgumentProvider {
 
+    public R1Unl(){
+        super(UnlSentences.R1);
+    }
+
     public static UnlDocumentNode buildSentenceNode() {
         var graph = new Graph();
 
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/R2Unl.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/R2Unl.java
index 78bf753..b036469 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/R2Unl.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/R2Unl.java
@@ -4,6 +4,10 @@ import java.util.*;
 
 public class R2Unl extends AbstractFlyweightUnlArgumentProvider {
 
+    public R2Unl(){
+        super(UnlSentences.R2);
+    }
+
     public static UnlDocumentNode buildSentenceNode() {
         var graph = new Graph();
 
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/UnlSentences.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/UnlSentences.java
index 50d9ee9..2eaec52 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/UnlSentences.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/UnlSentences.java
@@ -108,4 +108,30 @@ public class UnlSentences {
             "scn(respect(icl>consider>be,rsn>thing,obj>thing,aoj>person).@present.@promise,application(icl>information,equ>request,agt>thing,obj>uw))\n" +
             "{/unl}\n" +
             "[/S]\n";
+
+    public static final String Issue17 = "[S:00]\n" +
+            "{org:en}\n" +
+            "The system shall allow an operator to adjust the brightness of the POC touch panel while still leaving an operable screen for the operator (neither all white nor all black). \n" +
+            "{/org}\n" +
+            "{unl}\n" +
+            "agt(allow(icl>do,equ>permit,agt>volitional_thing,obj>uw,ben>volitional_thing).@entry.@present.@promise,system(icl>group>thing).@def)\n" +
+            "agt:02(adjust(icl>change>do,equ>correct,cob>thing,agt>volitional_thing,obj>thing).@entry,operator(icl>function>thing):01.@indef)\n" +
+            "obj:02(adjust(icl>change>do,equ>correct,cob>thing,agt>volitional_thing,obj>thing).@entry,brightness(icl>light>thing,ant>dullness).@def)\n" +
+            "mod:02(touch(icl>contact>thing),poc)\n" +
+            "mod:02(panel(icl>sheet>thing).@def,touch(icl>contact>thing))\n" +
+            "obj:02(brightness(icl>light>thing,ant>dullness).@def,panel(icl>sheet>thing).@def)\n" +
+            "dur:02(panel(icl>sheet>thing).@def,while(icl>how,equ>whilst,tim<uw,obj>uw))\n" +
+            "man:03(leave(icl>refrain>do,agt>thing,obj>thing,asp>thing).@entry,still(icl>how,com>duration))\n" +
+            "mod:03(screen(icl>surface>thing).@indef,operable(icl>adj))\n" +
+            "obj:03(leave(icl>refrain>do,agt>thing,obj>thing,asp>thing).@entry,screen(icl>surface>thing).@indef)\n" +
+            "ben:03(leave(icl>refrain>do,agt>thing,obj>thing,asp>thing).@entry,operator(icl>function>thing):02.@def)\n" +
+            "qua:01(white(icl>person>thing),all(icl>quantity,ant>some,per>thing):01)\n" +
+            "obj:01(neither_nor(icl>how,equ>nor,com>two_options,obj>uw,and<uw),white(icl>person>thing))\n" +
+            "and:01(black(icl>achromatic_color>thing,ant>white),neither_nor(icl>how,equ>nor,com>two_options,obj>uw,and<uw))\n" +
+            "qua:01(black(icl>achromatic_color>thing,ant>white),all(icl>quantity,ant>some,per>thing):02)\n" +
+            "cnt:03(operator(icl>function>thing):02.@def,:01.@parenthesis)\n" +
+            "obj(allow(icl>do,equ>permit,agt>volitional_thing,obj>uw,ben>volitional_thing).@entry.@present.@promise,:02)\n" +
+            "obj:02(while(icl>how,equ>whilst,tim<uw,obj>uw),:03)\n" +
+            "{/unl}\n" +
+            "[/S]\n";
 }
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/exporters/dot/DotFileBuilderTest.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/exporters/dot/DotFileBuilderTest.java
index daba156..398b56e 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/exporters/dot/DotFileBuilderTest.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/exporters/dot/DotFileBuilderTest.java
@@ -7,43 +7,64 @@ import org.junit.jupiter.api.Test;
 import java.io.StringWriter;
 import java.io.Writer;
 import java.util.List;
+import java.util.function.Function;
 
 class DotFileBuilderTest {
 
     @Test
     public void r1ShouldBeConvertedToDotFileWithoutException() {
-        writeInFile(new R1Unl().getUnlDocuments(), new R1SentenceWithExpectedDotChecker());
+        writeInFileAndCheckResultIsExpectedOne(new R1Unl().getUnlDocuments(), new R1SentenceWithExpectedDotChecker());
     }
 
     @Test
     public void r2ShouldBeConvertedToDotFileWithoutException() {
-        this.writeInFile(new R2Unl().getUnlDocuments(), new R2SentenceWithExpectedDotChecker());
+        this.writeInFileAndCheckResultIsExpectedOne(new R2Unl().getUnlDocuments(), new R2SentenceWithExpectedDotChecker());
     }
 
     @Test
     public void CatsShouldBeConvertedToDotFileWithoutException() {
-        this.writeInFile(new CatsUnl().getUnlDocuments(), new CatSentenceWithExpectedDotChecker());
+        this.writeInFileAndCheckResultIsExpectedOne(new CatsUnl().getUnlDocuments(), new CatSentenceWithExpectedDotChecker());
     }
 
     @Test
     public void allShouldBeConvertedToDotFileWithoutException() {
-        this.writeInFile(new AllUnl().getUnlDocuments(), new AllSetenceWithExpectedDotChecker());
+        this.writeInFileAndCheckResultIsExpectedOne(new AllUnl().getUnlDocuments(), new AllSetenceWithExpectedDotChecker());
     }
 
-    private void writeInFile(List<UnlDocument> unlDocuments, SentenceWithExpectedDotChecker sentenceChecker) {
+    @Test
+    public void Issue17ShouldBeConverterToDotFileWithoutException(){
+        this.shouldWriteInFileWithoutAnyException(new Issue17Unl().getUnlDocuments());
+    }
+
+    private void shouldWriteInFileWithoutAnyException(List<UnlDocument> unlDocuments) {
+        // Startup
+        Writer result = writeIntoWriterAndGetWriter(unlDocuments, this::createDotFileGraphExporter);
+        Assertions.assertDoesNotThrow(result::close);
+    }
+
+    private DotFileGraphExporter createDotFileGraphExporter(Writer writer){
+        return new DotFileGraphExporter(writer);
+    }
+
+    private void writeInFileAndCheckResultIsExpectedOne(List<UnlDocument> unlDocuments, SentenceWithExpectedDotChecker sentenceChecker) {
+        Writer strResult = writeIntoWriterAndGetWriter(unlDocuments, this::createDotFileGraphExporter);
+        sentenceChecker.setCurrentDotContent(strResult.toString());
+        sentenceChecker.assetSameAsExpected();
+        Assertions.assertDoesNotThrow(strResult::close);
+    }
+
+    private Writer writeIntoWriterAndGetWriter(List<UnlDocument> unlDocuments, Function<Writer, GraphExporter> exporterFactory) {
         // Startup
         Writer strResult = new StringWriter();
-        DotFileGraphExporter dotFileBuilder = new DotFileGraphExporter(strResult);
+        GraphExporter fileBuilder = exporterFactory.apply(strResult);
 
         // Test
-        Assertions.assertDoesNotThrow(() -> dotFileBuilder.write(unlDocuments));
+        Assertions.assertDoesNotThrow(() -> fileBuilder.write(unlDocuments));
 
         // Teardown
-        Assertions.assertDoesNotThrow(() -> strResult.flush());
+        Assertions.assertDoesNotThrow(strResult::flush);
         Assertions.assertTrue(() -> strResult.toString().length() != 0);
-        Assertions.assertDoesNotThrow(() -> sentenceChecker.setCurrentDotContent(strResult.toString()));
-        sentenceChecker.assetSameAsExpected();
-        Assertions.assertDoesNotThrow(() -> strResult.close());
 
+        return strResult;
     }
 }
\ No newline at end of file
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/Issue17SentenceWithExpectedUnlDocumentsChecker.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/Issue17SentenceWithExpectedUnlDocumentsChecker.java
new file mode 100644
index 0000000..0e3c462
--- /dev/null
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/Issue17SentenceWithExpectedUnlDocumentsChecker.java
@@ -0,0 +1,10 @@
+package fr.tetras_libre.unltools.unl.parser;
+
+import fr.tetras_libre.unltools.unl.Issue17Unl;
+import fr.tetras_libre.unltools.unl.UnlSentences;
+
+public class Issue17SentenceWithExpectedUnlDocumentsChecker extends SentenceWithExpectedUnlDocumentsChecker {
+    public Issue17SentenceWithExpectedUnlDocumentsChecker() {
+        super(UnlSentences.Issue17, new Issue17Unl().getUnlDocuments());
+    }
+}
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/UnlParserTest.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/UnlParserTest.java
index 4c77e1f..ea950da 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/UnlParserTest.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/UnlParserTest.java
@@ -1,8 +1,8 @@
 package fr.tetras_libre.unltools.unl.parser;
 
-import fr.tetras_libre.unltools.unl.UnlDocument;
 import fr.tetras_libre.unltools.unl.UnlSentences;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 import org.junit.jupiter.params.provider.ValueSource;
@@ -12,52 +12,71 @@ import java.util.stream.Stream;
 
 class UnlParserTest {
 
-    private static Stream<SentenceWithExpectedUnlDocumentsChecker> unlParserShouldParseSentenceAndGetExpectedUnlDocuments() {
+    private static Stream<SentenceWithExpectedUnlDocumentsChecker> SentenceWithExpectedUnlDocumentsCheckerStream() {
         return Stream.of(new R1SentenceWithExpectedUnlDocumentsChecker(),
-            new R2SentenceWithExpectedUnlDocumentsChecker(),
-            new CatsSentenceWithExpectedUnlDocumentsChecker(),
-            new AllSentenceWithExpectedUnlDocumentsChecker(),
-            new Issue13WithExpectedUnlDocumentChecker());
+                new R2SentenceWithExpectedUnlDocumentsChecker(),
+                new CatsSentenceWithExpectedUnlDocumentsChecker(),
+                new AllSentenceWithExpectedUnlDocumentsChecker(),
+                new Issue13WithExpectedUnlDocumentChecker(),
+                new Issue17SentenceWithExpectedUnlDocumentsChecker());
     }
 
     @ParameterizedTest
-    @ValueSource(strings = {UnlSentences.R1, UnlSentences.R2, UnlSentences.Cats, UnlSentences.All, UnlSentences.Issue13})
-    void unlParserShouldParseSimpleSentenceWithoutException(String input) {
-        UnlParserFactory unlFactory = new UnlParserFactoryFromString(input);
-        var wrapper = createAndCheckUnlParserValidity(unlFactory);
+    @ValueSource(strings = {UnlSentences.R1, UnlSentences.R2, UnlSentences.Cats, UnlSentences.All, UnlSentences.Issue13, UnlSentences.Issue17})
+    void unlParserShouldParseSentencesWithoutException(String input) {
+        unlParserShouldParseOneSentenceWithoutException(input);
+    }
 
-        for (UnlDocument unlDocument : wrapper.getUnlDocumentList()) {
-            AtomicReference<String> stringOfUnlDocument = new AtomicReference<>();
-            Assertions.assertDoesNotThrow(() -> stringOfUnlDocument.set(unlDocument.toString()));
-        }
+    /**
+     * Check that the current unlString can be converted to UnlDocuments without any exception.
+     *
+     * @param unlString The unl text to parse.
+     */
+    WrapperUnlParser unlParserShouldParseOneSentenceWithoutException(String unlString) {
+        UnlParserFactory unlFactory = new UnlParserFactoryFromString(unlString);
+        return createAndCheckUnlParseValidity(unlFactory);
     }
 
     /**
      * Check validity of parser:
      * - It checks the creation of parser
+     * - It Checks the parser parse without occurring exception
      * - It checks the content of document doesn't contain an error
      *
      * @param factory A factory of UnlParser
      * @return An unlParserWrapper
      */
-    WrapperUnlParser createAndCheckUnlParserValidity(UnlParserFactory factory) {
+    WrapperUnlParser createAndCheckUnlParseValidity(UnlParserFactory factory) {
         AtomicReference<WrapperUnlParser> unlParser = new AtomicReference<>();
 
         Assertions.assertDoesNotThrow(() -> unlParser.set(factory.create()), "");
         Assertions.assertNotNull(unlParser.get(), "The parse should exists");
+
+        Assertions.assertDoesNotThrow(() -> unlParser.get().parseUnlSource());
         Assertions.assertFalse(unlParser.get().hasError(), String.format("Current error: '%s'", String.join(",", unlParser.get().getErrors())));
 
         return unlParser.get();
     }
 
     @ParameterizedTest
-    @MethodSource
-    void unlParserShouldParseSentenceAndGetExpectedUnlDocuments(SentenceWithExpectedUnlDocumentsChecker input) {
-        UnlParserFactory unlFactory = new UnlParserFactoryFromString(input.getUnlSentence());
-        var wrapper = createAndCheckUnlParserValidity(unlFactory);
+    @MethodSource("SentenceWithExpectedUnlDocumentsCheckerStream")
+    void unlParserShouldParseAllSentencesAndGetExpectedUnlDocuments(SentenceWithExpectedUnlDocumentsChecker input) {
+        unlParserShouldParseSentenceAndGetExpectedUnlDocuments(input);
+    }
 
+    void unlParserShouldParseSentenceAndGetExpectedUnlDocuments(SentenceWithExpectedUnlDocumentsChecker input) {
+        var wrapper = unlParserShouldParseOneSentenceWithoutException(input.getUnlSentence());
         input.setCurrentUnlDocuments(wrapper.getUnlDocumentList());
         input.assetSameAsExpected();
     }
 
+    @Test
+    void unlParserShouldParseCorrectlyOneUnlString() {
+        unlParserShouldParseOneSentenceWithoutException(UnlSentences.Issue17);
+    }
+
+    @Test
+    void unlParserShouldParseOneUnlStringAndGetExpectedUnlDocuments() {
+        unlParserShouldParseSentenceAndGetExpectedUnlDocuments(new Issue17SentenceWithExpectedUnlDocumentsChecker());
+    }
 }
\ No newline at end of file
diff --git a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/WrapperUnlParser.java b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/WrapperUnlParser.java
index cd4cb33..50d10a3 100644
--- a/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/WrapperUnlParser.java
+++ b/unl-tools-infrastructure/src/test/java/fr/tetras_libre/unltools/unl/parser/WrapperUnlParser.java
@@ -5,7 +5,7 @@ import fr.tetras_libre.unltools.unl.UnlDocument;
 import java.util.Vector;
 
 public class WrapperUnlParser {
-    private final UnlParser parser;
+    private UnlParser parser;
     private Vector<UnlDocument> documents;
     private ErrorCollection errors;
 
@@ -25,6 +25,10 @@ public class WrapperUnlParser {
         return this.documents;
     }
 
+    public void parseUnlSource(){
+        parseContentAndRetrieveErrors();
+    }
+
     /**
      * Parse the content with the local parser if not already done.
      */
diff --git a/unl-tools-main/src/main/java/unl2rdf/Unl2Rdf.java b/unl-tools-main/src/main/java/unl2rdf/Unl2Rdf.java
index 555b7e7..973c466 100644
--- a/unl-tools-main/src/main/java/unl2rdf/Unl2Rdf.java
+++ b/unl-tools-main/src/main/java/unl2rdf/Unl2Rdf.java
@@ -33,7 +33,7 @@ public class Unl2Rdf {
     }
 
     private static void runProgram(Options options) throws IOException {
-        System.out.println(String.format("Source file :  '%s'", options.getInputFile().getAbsolutePath()));
+        System.out.printf("Source file :  '%s'%n", options.getInputFile().getAbsolutePath());
 
 
         var importer = UnlGraphImporterFromUnlParser.FromInputReader(options.getInputStream());
@@ -46,7 +46,7 @@ public class Unl2Rdf {
             var convertCommand = new ExportUnlDocuments(importer, GetExporterName(outType), fileWriter);
             handler.handle(convertCommand);
             fileWriter.close();
-            System.out.println(String.format("Graph writen into file '%s'", outfileName));
+            System.out.printf("Graph written into file '%s'%n", outfileName);
         }
     }
 
-- 
GitLab