text: /*
   * $Id$
   *
   * Copyright (C) 2003-2015 JNode.org
   *
   * This library is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as published
   * by the Free Software Foundation; either version 2.1 of the License, or
   * (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful, but 
   * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
   * License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with this library; If not, write to the Free Software Foundation, Inc., 
   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   */
   
  package org.jnode.test.shell.syntax;
  
  import org.jnode.shell.CommandLine;
  import org.jnode.shell.NoTokensAvailableException;
  import org.jnode.shell.syntax.CommandSyntaxException;
  import org.jnode.shell.syntax.MuAlternation;
  import org.jnode.shell.syntax.MuBackReference;
  import org.jnode.shell.syntax.MuParser;
  import org.jnode.shell.syntax.MuSequence;
  import org.jnode.shell.syntax.MuSymbol;
  import org.jnode.shell.syntax.MuSyntax;
  import org.jnode.shell.syntax.SyntaxFailureException;
  import org.junit.Assert;
  import org.junit.Test;
  
  @SuppressWarnings("deprecation")
  public class MuParserTest {
  
      @Test
      public void testInstantiation() {
          new MuParser();
      }
  
      @Test
      public void testStatelessParsing1() throws NoTokensAvailableException, CommandSyntaxException {
          // <start> ::= 'a'
          MuSyntax syntax = new MuSymbol("a");
          MuParser parser = new MuParser();
          CommandLine cl;
  
          cl = new CommandLine(new String[] {"a"});
  
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          try {
              cl = new CommandLine(new String[] {"b"});
              parser.parse(syntax, null, cl.tokenIterator(), null);
              Assert.fail("parse didn't fail");
          } catch (CommandSyntaxException ex) {
              // expected
          }
  
          try {
              cl = new CommandLine(new String[] {"a", "a"});
              parser.parse(syntax, null, cl.tokenIterator(), null);
              Assert.fail("parse didn't fail");
          } catch (CommandSyntaxException ex) {
              // expected
          }
      }
  
      @Test
      public void testStatelessParsing2() throws NoTokensAvailableException, CommandSyntaxException {
          // <start> ::= 'a' 'b'
          MuSyntax syntax = new MuSequence(new MuSymbol("a"), new MuSymbol("b"));
          MuParser parser = new MuParser();
          CommandLine cl;
  
          cl = new CommandLine(new String[] {"a", "b"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
          try {
              cl = new CommandLine(new String[] {"a"});
              parser.parse(syntax, null, cl.tokenIterator(), null);
              Assert.fail("parse didn't fail");
          } catch (CommandSyntaxException ex) {
              // expected
          }
          try {
              cl = new CommandLine(new String[] {"a"});
              parser.parse(syntax, null, cl.tokenIterator(), null);
              Assert.fail("parse didn't fail");
          } catch (CommandSyntaxException ex) {
              // expected
          }
      }
  
      @Test
      public void testStatelessParsing3() throws NoTokensAvailableException, CommandSyntaxException {
          // <start> :: = 'a' | 'b'
          MuSyntax syntax = new MuAlternation(new MuSymbol("a"), new MuSymbol("b"));
          MuParser parser = new MuParser();
          CommandLine cl;
  
          cl = new CommandLine(new String[] {"a"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          cl = new CommandLine(new String[] {"b"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          try {
              cl = new CommandLine(new String[] {"c"});
              parser.parse(syntax, null, cl.tokenIterator(), null);
              Assert.fail("parse didn't fail");
          } catch (CommandSyntaxException ex) {
              // expected
          }
      }
  
      @Test
      public void testStatelessParsing4() throws NoTokensAvailableException, CommandSyntaxException {
          // <root> ::= 'b' | ( 'a' <root> )
          MuSyntax syntax =
                  new MuAlternation("root", new MuSymbol("b"), new MuSequence(new MuSymbol("a"),
                          new MuBackReference("root")));
          MuParser parser = new MuParser();
          CommandLine cl;
  
          cl = new CommandLine(new String[] {"b"});
  
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          try {
              cl = new CommandLine(new String[] {"a", "b"});
              parser.parse(syntax, null, cl.tokenIterator(), null);
              Assert.fail("expected SFE");
          } catch (SyntaxFailureException ex) {
              // expected
          }
  
          syntax.resolveBackReferences();
          cl = new CommandLine(new String[] {"a", "b"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          cl = new CommandLine(new String[] {"a", "a", "b"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          try {
              cl = new CommandLine(new String[] {"a", "a", "c"});
              parser.parse(syntax, null, cl.tokenIterator(), null);
              Assert.fail("expected SEE");
          } catch (CommandSyntaxException ex) {
              // expected
          }
      }
  
      @Test
      public void testStatelessParsing5() throws NoTokensAvailableException, CommandSyntaxException {
          // <root> ::= ( 'a' <root> ) | 'b'
          MuSyntax syntax =
                  new MuAlternation("root", new MuSequence(new MuSymbol("a"), new MuBackReference(
                          "root")), new MuSymbol("b"));
          MuParser parser = new MuParser();
          CommandLine cl;
  
          syntax.resolveBackReferences();
  
          cl = new CommandLine(new String[] {"b"});
  
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          syntax.resolveBackReferences();
          cl = new CommandLine(new String[] {"a", "b"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          cl = new CommandLine(new String[] {"a", "a", "b"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          try {
              cl = new CommandLine(new String[] {"a", "a", "c"});
              parser.parse(syntax, null, cl.tokenIterator(), null);
              Assert.fail("expected SEE");
          } catch (CommandSyntaxException ex) {
              // expected
          }
      }
  
      @Test
      public void testStatelessParsing6() throws NoTokensAvailableException, CommandSyntaxException {
          // <root> ::= ( ( 'a' <root> ) | ( 'b' 'c' ) ) | ( ( 'a' <root> ) | 'b'
          // ) )
          MuSyntax syntax = new MuAlternation("root", new MuAlternation(new MuSequence(new MuSymbol("a"),
              new MuBackReference("root")), new MuSequence(new MuSymbol("b"), new MuSymbol("c"))),
              new MuAlternation(new MuSequence(new MuSymbol("a"), new MuBackReference("root")), new MuSymbol("b")));
          MuParser parser = new MuParser();
          CommandLine cl;
  
          syntax.resolveBackReferences();
  
          cl = new CommandLine(new String[] {"b"});
  
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          syntax.resolveBackReferences();
          cl = new CommandLine(new String[] {"a", "b"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          cl = new CommandLine(new String[] {"a", "a", "b"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          cl = new CommandLine(new String[] {"a", "a", "b", "c"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          try {
              cl = new CommandLine(new String[] {"a", "a", "c"});
              parser.parse(syntax, null, cl.tokenIterator(), null);
              Assert.fail("expected SEE");
          } catch (CommandSyntaxException ex) {
              // expected
          }
      }
  
      @Test
      public void testPathological() throws NoTokensAvailableException, CommandSyntaxException {
          // Pathological grammar.
          // <root> ::= 'b' | ( <root> <root> )
          MuSyntax syntax =
                  new MuAlternation("root", new MuSymbol("b"), new MuSequence(new MuBackReference(
                          "root"), new MuBackReference("root")));
          MuParser parser = new MuParser();
          CommandLine cl;
  
          syntax.resolveBackReferences();
  
          // This doesn't hit the infinite loop ...
          cl = new CommandLine(new String[] {"b"});
          parser.parse(syntax, null, cl.tokenIterator(), null);
  
          // But this does ...
          cl = new CommandLine(new String[] {"a"});
          try {
              parser.parse(syntax, null, cl.tokenIterator(), null);
              Assert.fail("expected SFE");
          } catch (SyntaxFailureException ex) {
              Assert.assertEquals(
                      "Parse exceeded the step limit (" + MuParser.DEFAULT_STEP_LIMIT + "). " +
                              "Either the command line is too large, or the syntax is too complex (or pathological)",
                      ex.getMessage());
          }
      }
  }
  