changeset 1713:a1f58895a63f

Allow single quoted args in thermostat shell Enhance ShellArgsParser to also handle single quote marks, not only double quote marks Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-July/014410.html
author Andrew Azores <aazores@redhat.com>
date Tue, 07 Jul 2015 12:23:45 -0400
parents b2a64131e8a6
children d9f3dd1eaed2
files launcher/src/main/java/com/redhat/thermostat/launcher/internal/ShellArgsParser.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/ShellArgsParserTest.java
diffstat 2 files changed, 150 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/ShellArgsParser.java	Tue Jul 07 12:23:20 2015 -0400
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/ShellArgsParser.java	Tue Jul 07 12:23:45 2015 -0400
@@ -60,7 +60,6 @@
     private final String input;
     private int pos = NOT_YET_PARSED;
     private char c;
-    private int quoteCount = 0;
     private final Issues issues = new Issues();
 
     ShellArgsParser(String input) {
@@ -103,6 +102,7 @@
         StringBuilder sb = new StringBuilder();
         boolean closed = false;
         int startPos = pos;
+        char openingQuote = c;
         while (ready()) {
             readChar();
             if (isEscapedQuote()) {
@@ -110,7 +110,7 @@
                 sb.append(c);
                 continue;
             }
-            if (isQuote()) {
+            if (c == openingQuote) {
                 if (ready()) {
                     readChar();
                     if (!ready()) {
@@ -172,11 +172,11 @@
     }
 
     private boolean isEscapedQuote() {
-        return c == '\\' && lookahead() == '"';
+        return c == '\\' && (lookahead() == '"' || lookahead() == '\'');
     }
 
     private boolean isQuote() {
-        return c == '"';
+        return c == '"' || c == '\'';
     }
 
     private boolean isWhitespace() {
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ShellArgsParserTest.java	Tue Jul 07 12:23:20 2015 -0400
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ShellArgsParserTest.java	Tue Jul 07 12:23:45 2015 -0400
@@ -38,7 +38,6 @@
 
 import org.junit.Test;
 
-import java.util.Arrays;
 import java.util.List;
 
 import static org.hamcrest.CoreMatchers.equalTo;
@@ -135,57 +134,117 @@
     }
 
     @Test
+    public void testSingleQuotedArg() {
+        assertResult("'foo'", "foo");
+        assertNoIssues();
+    }
+
+    @Test
     public void testQuotedString() {
         assertResult("\"foo bar\"", "foo bar");
         assertNoIssues();
     }
 
     @Test
+    public void testSingleQuotedString() {
+        assertResult("'foo bar'", "foo bar");
+        assertNoIssues();
+    }
+
+    @Test
     public void testQuotedArgFirst() {
         assertResult("\"foo bar\" baz", "foo bar", "baz");
         assertNoIssues();
     }
 
     @Test
+    public void testSingleQuotedArgFirst() {
+        assertResult("'foo bar' baz", "foo bar", "baz");
+        assertNoIssues();
+    }
+
+    @Test
     public void testSingleStartingQuote() {
         assertResult("\"foo", "foo");
         assertIssues(new ShellArgsParser.Issue(0, ShellArgsParser.Issue.Type.UNMATCHED_QUOTE));
     }
 
     @Test
+    public void testSingleStartingSingleQuote() {
+        assertResult("'foo", "foo");
+        assertIssues(new ShellArgsParser.Issue(0, ShellArgsParser.Issue.Type.UNMATCHED_QUOTE));
+    }
+
+    @Test
     public void testSingleEndingQuote() {
         assertResult("foo\"", "foo\"");
         assertIssues(new ShellArgsParser.Issue(3, ShellArgsParser.Issue.Type.UNEXPECTED_QUOTE));
     }
 
     @Test
+    public void testSingleEndingSingleQuote() {
+        assertResult("foo'", "foo'");
+        assertIssues(new ShellArgsParser.Issue(3, ShellArgsParser.Issue.Type.UNEXPECTED_QUOTE));
+    }
+
+    @Test
     public void testSingleMiddleQuote() {
         assertResult("foo \" bar", "foo", " bar");
         assertIssues(new ShellArgsParser.Issue(4, ShellArgsParser.Issue.Type.UNMATCHED_QUOTE));
     }
 
     @Test
+    public void testSingleMiddleSingleQuote() {
+        assertResult("foo ' bar", "foo", " bar");
+        assertIssues(new ShellArgsParser.Issue(4, ShellArgsParser.Issue.Type.UNMATCHED_QUOTE));
+    }
+
+    @Test
     public void testOneQuoteMark() {
         assertResult("\"", "");
         assertIssues(new ShellArgsParser.Issue(0, ShellArgsParser.Issue.Type.UNMATCHED_QUOTE));
     }
 
     @Test
+    public void testOneSingleQuoteMark() {
+        assertResult("'", "");
+        assertIssues(new ShellArgsParser.Issue(0, ShellArgsParser.Issue.Type.UNMATCHED_QUOTE));
+    }
+
+    @Test
     public void testThreeQuoteMarks() {
         assertResult("\"\"\"", "");
         assertIssues(new ShellArgsParser.Issue(2, ShellArgsParser.Issue.Type.UNMATCHED_QUOTE));
     }
 
     @Test
+    public void testThreeSingleQuoteMarks() {
+        assertResult("'''", "");
+        assertIssues(new ShellArgsParser.Issue(2, ShellArgsParser.Issue.Type.UNMATCHED_QUOTE));
+    }
+
+    @Test
     public void testFourQuoteMarks() {
         assertResult("\"\"\"\"", "", "");
         assertIssues(new ShellArgsParser.Issue(2, ShellArgsParser.Issue.Type.EXPECTED_WHITESPACE));
     }
 
     @Test
+    public void testFourSingleQuoteMarks() {
+        assertResult("''''", "", "");
+        assertIssues(new ShellArgsParser.Issue(2, ShellArgsParser.Issue.Type.EXPECTED_WHITESPACE));
+    }
+
+    @Test
     public void testAdjacentQuotes() {
         assertResult("\"f\"\"b\"", "f", "b");
-        assertIssues(new ShellArgsParser.Issue(3 , ShellArgsParser.Issue.Type.EXPECTED_WHITESPACE));
+        assertIssues(new ShellArgsParser.Issue(3, ShellArgsParser.Issue.Type.EXPECTED_WHITESPACE));
+    }
+
+    @Test
+    public void testAdjacentSingleQuotes() {
+        assertResult("'f''b'", "f", "b");
+        assertIssues(new ShellArgsParser.Issue(3, ShellArgsParser.Issue.Type.EXPECTED_WHITESPACE));
     }
 
     @Test
@@ -196,12 +255,25 @@
     }
 
     @Test
+    public void testSingleQuoteAdjacentToWord() {
+        assertResult("foo'bar'", "foo'bar'");
+        assertIssues(new ShellArgsParser.Issue(3, ShellArgsParser.Issue.Type.UNEXPECTED_QUOTE),
+                new ShellArgsParser.Issue(7, ShellArgsParser.Issue.Type.UNEXPECTED_QUOTE));
+    }
+
+    @Test
     public void testSingleEscapedQuote() {
         assertResult("foo\\\"", "foo\"");
         assertNoIssues();
     }
 
     @Test
+    public void testSingleEscapedSingleQuote() {
+        assertResult("foo\\'", "foo'");
+        assertNoIssues();
+    }
+
+    @Test
     public void testQuoteContainingEscapedQuoteLiteral() {
         assertResult("\"foo \\\" bar\"", "foo \" bar");
         assertNoIssues();
@@ -214,18 +286,90 @@
     }
 
     @Test
+    public void testSingleQuoteContainingEscapedSingleQuoteLiteral() {
+        assertResult("'foo \\' bar'", "foo ' bar");
+        assertNoIssues();
+    }
+
+    @Test
+    public void testQuoteContainingEscapedSingleQuoteLiteral2() {
+        assertResult("\"foo \\\"\"", "foo \"");
+        assertNoIssues();
+    }
+
+    @Test
+    public void testQuoteContainingEscapedSingleSingleQuoteLiteral2() {
+        assertResult("'foo \\''", "foo '");
+        assertNoIssues();
+    }
+
+    @Test
+    public void testEscapedQuoteInsideSingleQuotes() {
+        assertResult("'foo \\\" bar'", "foo \" bar");
+        assertNoIssues();
+    }
+
+    @Test
+    public void testEscapedSingleQuoteInsideQuotes() {
+        assertResult("\"foo \\' bar\"", "foo ' bar");
+        assertNoIssues();
+    }
+
+    @Test
     public void testQuotedEmptyString() {
         assertResult("\"\"", "");
         assertNoIssues();
     }
 
     @Test
+    public void testSingleQuotedEmptyString() {
+        assertResult("''", "");
+        assertNoIssues();
+    }
+
+    @Test
     public void testQuotedSpacesString() {
         assertResult("\" \"", " ");
         assertNoIssues();
     }
 
     @Test
+    public void testSingleQuotedSpacesString() {
+        assertResult("' '", " ");
+        assertNoIssues();
+    }
+
+    @Test
+    public void testSingleAndDoubleQuotes() {
+        assertResult("\"foo\" 'bar'", "foo", "bar");
+        assertNoIssues();
+    }
+
+    @Test
+    public void testSingleQuotesWithinDoubleQuotes() {
+        assertResult("\"some 'quoted' args\"", "some 'quoted' args");
+        assertNoIssues();
+    }
+
+    @Test
+    public void testDoubleQuotesWithinSingleQuotes() {
+        assertResult("'some \"quoted\" args'", "some \"quoted\" args");
+        assertNoIssues();
+    }
+
+    @Test
+    public void testSingleAndDoubleQuotesAdjacent() {
+        assertResult("\"foo\"'bar'", "foo", "bar");
+        assertIssues(new ShellArgsParser.Issue(5, ShellArgsParser.Issue.Type.EXPECTED_WHITESPACE));
+    }
+
+    @Test
+    public void testMismatchedQuotes() {
+        assertResult("\"foo'", "foo'");
+        assertIssues(new ShellArgsParser.Issue(0, ShellArgsParser.Issue.Type.UNMATCHED_QUOTE));
+    }
+
+    @Test
     public void testIssueGetters() {
         ShellArgsParser.Issue issue = new ShellArgsParser.Issue(10, ShellArgsParser.Issue.Type.UNEXPECTED_QUOTE);
         int columnNumber = issue.getColumnNumber();