Coverage Report - net.sf.jmatchparser.util.ExpectReader
 
Classes in this File Line Coverage Branch Coverage Complexity
ExpectReader
90%
57/63
82%
23/28
1,917
 
 1  
 /*
 2  
  * Copyright (c) 2006 - 2011 Michael Schierl
 3  
  * 
 4  
  * All rights reserved.
 5  
  * 
 6  
  * Redistribution and use in source and binary forms, with or without
 7  
  * modification, are permitted provided that the following conditions
 8  
  * are met:
 9  
  * 
 10  
  * - Redistributions of source code must retain the above copyright notice,
 11  
  *   this list of conditions and the following disclaimer.
 12  
  *   
 13  
  * - Redistributions in binary form must reproduce the above copyright
 14  
  *   notice, this list of conditions and the following disclaimer in the
 15  
  *   documentation and/or other materials provided with the distribution.
 16  
  *   
 17  
  * - Neither name of the copyright holders nor the names of its
 18  
  *   contributors may be used to endorse or promote products derived from
 19  
  *   this software without specific prior written permission.
 20  
  *   
 21  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND THE CONTRIBUTORS
 22  
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 23  
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 24  
  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 25  
  * HOLDERS OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 26  
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 27  
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 28  
  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 29  
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 30  
  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 31  
  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 32  
  */
 33  
 package net.sf.jmatchparser.util;
 34  
 
 35  
 import java.util.ArrayList;
 36  
 import java.util.List;
 37  
 import java.io.BufferedReader;
 38  
 import java.io.EOFException;
 39  
 import java.io.IOException;
 40  
 import java.io.InputStream;
 41  
 import java.io.InputStreamReader;
 42  
 import java.io.Reader;
 43  
 import java.io.UnsupportedEncodingException;
 44  
 import java.util.regex.Matcher;
 45  
 import java.util.regex.Pattern;
 46  
 
 47  
 /**
 48  
  * A fairly simple reader class, that can "expect" constant text and regular
 49  
  * expressions, while still leaving full control to the programmer. This parser
 50  
  * is fully deterministic; therefore, using it on more complex documents can be
 51  
  * quite frustrating. Basically, this is what I used before I wrote
 52  
  * JMatchParser. It is included because I still have old projects using it, and
 53  
  * because it might be useful for simple projects.
 54  
  */
 55  
 public class ExpectReader {
 56  
 
 57  
         private final BufferedReader br;
 58  
 
 59  
         /**
 60  
          * Create a new expect reader reading from the given {@link BufferedReader}.
 61  
          */
 62  6
         public ExpectReader(BufferedReader br) {
 63  6
                 this.br = br;
 64  6
         }
 65  
 
 66  
         /**
 67  
          * Create a new expect reader reading from the given {@link Reader}.
 68  
          */
 69  
         public ExpectReader(Reader r) {
 70  5
                 this(new BufferedReader(r));
 71  5
         }
 72  
 
 73  
         /**
 74  
          * Create a new expect reader reading from the given {@link InputStream}.
 75  
          */
 76  
         public ExpectReader(InputStream in, String charsetName) throws UnsupportedEncodingException {
 77  1
                 this(new InputStreamReader(in, charsetName));
 78  1
         }
 79  
 
 80  
         // generic methods
 81  
 
 82  
         /**
 83  
          * Return the reader used.
 84  
          */
 85  
         public BufferedReader getReader() {
 86  3
                 return br;
 87  
         }
 88  
 
 89  
         /**
 90  
          * Read a line from the reader, and return it. Throw an exception if eof is
 91  
          * reached before reading the line.
 92  
          */
 93  
         public String ensureReadLine() throws IOException {
 94  24
                 String l = readLine();
 95  24
                 if (l == null)
 96  0
                         throw new EOFException();
 97  24
                 return l;
 98  
         }
 99  
 
 100  
         /**
 101  
          * Read a line like {@link #ensureReadLine()}, but trim the response and
 102  
          * skip empty lines.
 103  
          */
 104  
         public String ensureReadTrimmedLine() throws IOException {
 105  7
                 String l = ensureReadLine().trim();
 106  16
                 while (l.length() == 0) {
 107  9
                         l = ensureReadLine().trim();
 108  
                 }
 109  7
                 return l;
 110  
         }
 111  
 
 112  
         /**
 113  
          * Read a line.
 114  
          * 
 115  
          * @see BufferedReader#readLine()
 116  
          */
 117  
         public String readLine() throws IOException {
 118  25
                 return br.readLine();
 119  
         }
 120  
 
 121  
         /**
 122  
          * Ensure that the end of file has been reached.
 123  
          */
 124  
         public void ensureEndOfFile() throws IOException {
 125  2
                 if (br.readLine() != null)
 126  0
                         throw new IOException("Not at end of file");
 127  2
         }
 128  
 
 129  
         /**
 130  
          * Close the underlying reader.
 131  
          */
 132  
         public void close() throws IOException {
 133  2
                 br.close();
 134  2
         }
 135  
 
 136  
         // string matches
 137  
 
 138  
         /**
 139  
          * Expect one ore more lines.
 140  
          * 
 141  
          * @see #expectLine(String)
 142  
          */
 143  
         public void expect(String... lines) throws IOException {
 144  6
                 for (String l : lines) {
 145  4
                         expectLine(l);
 146  
                 }
 147  2
         }
 148  
 
 149  
         /**
 150  
          * Expect one ore more trimmed lines.
 151  
          * 
 152  
          * @see #expectTrimmedLine(String)
 153  
          */
 154  
         public void expectTrimmed(String... lines) throws IOException {
 155  6
                 for (String l : lines) {
 156  5
                         expectTrimmedLine(l);
 157  
                 }
 158  1
         }
 159  
 
 160  
         /**
 161  
          * Expect a line. If the {@link Reader}'s next line does not match the line
 162  
          * given, an exception is thrown.
 163  
          */
 164  
         public void expectLine(String line) throws IOException {
 165  5
                 ensureStringMatch(ensureReadLine(), line);
 166  5
         }
 167  
 
 168  
         /**
 169  
          * Expect a trimmed. If the {@link Reader}'s next line does not match the
 170  
          * line given, after trimming, an exception is thrown.
 171  
          * 
 172  
          * For symmetry reasons, calling this method with an empty string is a
 173  
          * no-op.
 174  
          */
 175  
         public void expectTrimmedLine(String line) throws IOException {
 176  6
                 if (line.trim().length() == 0)
 177  2
                         return;
 178  4
                 ensureStringMatch(ensureReadTrimmedLine(), line.trim());
 179  4
         }
 180  
 
 181  
         /**
 182  
          * Ensure that two strings are the same.
 183  
          * 
 184  
          * @param actual
 185  
          *            The actual string
 186  
          * @param expected
 187  
          *            The expected string
 188  
          */
 189  
         public static void ensureStringMatch(String actual, String expected) {
 190  10
                 if (!expected.equals(actual)) {
 191  0
                         throw new ExpectException(actual, expected);
 192  
                 }
 193  10
         }
 194  
 
 195  
         // regex matches
 196  
 
 197  
         /**
 198  
          * Expect a line that matches a regex. A {@link Matcher} to read the groups
 199  
          * is returned.
 200  
          */
 201  
         public Matcher expectRegex(String regex) throws IOException {
 202  1
                 return ensureRegexMatch(ensureReadLine(), regex);
 203  
         }
 204  
 
 205  
         /**
 206  
          * Expect a line that matches a regex. A {@link Matcher} to read the groups
 207  
          * is returned.
 208  
          */
 209  
         public Matcher expectRegex(Pattern pattern) throws IOException {
 210  1
                 return ensureRegexMatch(ensureReadLine(), pattern);
 211  
         }
 212  
 
 213  
         /**
 214  
          * Expect a trimmed line that matches a regex. A {@link Matcher} to read the
 215  
          * groups is returned.
 216  
          * 
 217  
          * @see #ensureReadTrimmedLine()
 218  
          */
 219  
         public Matcher expectTrimmedRegex(String regex) throws IOException {
 220  1
                 return ensureRegexMatch(ensureReadTrimmedLine(), regex);
 221  
         }
 222  
 
 223  
         /**
 224  
          * Expect a trimmed line that matches a regex. A {@link Matcher} to read the
 225  
          * groups is returned.
 226  
          * 
 227  
          * @see #ensureReadTrimmedLine()
 228  
          */
 229  
         public Matcher expectTrimmedRegex(Pattern pattern) throws IOException {
 230  1
                 return ensureRegexMatch(ensureReadTrimmedLine(), pattern);
 231  
         }
 232  
 
 233  
         /**
 234  
          * Ensure that a string matches a pattern and returns a {@link Matcher}.
 235  
          * 
 236  
          * @param actual
 237  
          *            The actual string
 238  
          * @param pattern
 239  
          *            The pattern
 240  
          */
 241  
         public static Matcher ensureRegexMatch(String actual, String pattern) {
 242  3
                 return ensureRegexMatch(actual, PatternCache.compile(pattern));
 243  
         }
 244  
 
 245  
         /**
 246  
          * Ensure that a string matches a pattern and returns a {@link Matcher}.
 247  
          * 
 248  
          * @param actual
 249  
          *            The actual string
 250  
          * @param pattern
 251  
          *            The pattern
 252  
          */
 253  
         public static Matcher ensureRegexMatch(String actual, Pattern pattern) {
 254  6
                 Matcher m = regexMatch(actual, pattern);
 255  6
                 if (m == null)
 256  0
                         throw ExpectException.fromRegex(actual, pattern);
 257  6
                 return m;
 258  
         }
 259  
 
 260  
         /**
 261  
          * Try to match a string against pattern and returns a {@link Matcher} or
 262  
          * <code>null</code>.
 263  
          * 
 264  
          * @param actual
 265  
          *            The actual string
 266  
          * @param pattern
 267  
          *            The pattern
 268  
          */
 269  
         public static Matcher regexMatch(String actual, String pattern) {
 270  0
                 return regexMatch(actual, PatternCache.compile(pattern));
 271  
         }
 272  
 
 273  
         /**
 274  
          * Try to match a string against pattern and returns a {@link Matcher} or
 275  
          * <code>null</code>.
 276  
          * 
 277  
          * @param actual
 278  
          *            The actual string
 279  
          * @param pattern
 280  
          *            The pattern
 281  
          */
 282  
         public static Matcher regexMatch(String actual, Pattern pattern) {
 283  8
                 Matcher m = pattern.matcher(actual);
 284  8
                 if (m.matches()) {
 285  7
                         return m;
 286  
                 }
 287  1
                 return null;
 288  
         }
 289  
 
 290  
         // multi regex match
 291  
 
 292  
         /**
 293  
          * Perform a multi regex match.
 294  
          * 
 295  
          * @see #ensureMultiRegexMatch(String, Pattern, Pattern, int)
 296  
          */
 297  
         public static List<Matcher> ensureMultiRegexMatch(String actual, String regex, String terminalRegex, int restGroup) {
 298  2
                 return ensureMultiRegexMatch(actual, PatternCache.compile(regex),
 299  
                                 terminalRegex == null ? null : PatternCache.compile(terminalRegex),
 300  
                                                 restGroup);
 301  
         }
 302  
 
 303  
         /**
 304  
          * Perform a multi regex match.
 305  
          * 
 306  
          * <p>
 307  
          * If terminalPattern is non-<code>null</code>: Match actual against the
 308  
          * terminal pattern. If it matches, the match is finished. If not, it is
 309  
          * matched against the pattern and added to the result list (non-match is an
 310  
          * error). The restGroup'th group of the matcher is then used as the actual
 311  
          * value for the next round.
 312  
          * 
 313  
          * <p>
 314  
          * If terminalPattern is <code>null</code>: Terminate when it does not match
 315  
          * any longer. Rest as above.
 316  
          */
 317  
         public static List<Matcher> ensureMultiRegexMatch(String actual, Pattern pattern, Pattern terminalPattern, int restGroup) {
 318  4
                 List<Matcher> result = new ArrayList<Matcher>();
 319  21
                 while (terminalPattern == null || !terminalPattern.matcher(actual).matches()) {
 320  19
                         Matcher m = pattern.matcher(actual);
 321  19
                         if (!m.matches()) {
 322  2
                                 if (terminalPattern == null)
 323  2
                                         return result;
 324  0
                                 throw ExpectException.fromRegex(actual, pattern);
 325  
                         }
 326  17
                         result.add(m);
 327  17
                         actual = m.group(restGroup);
 328  17
                 }
 329  2
                 return result;
 330  
         }
 331  
 }