diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/YangUtilsParserManager.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/YangUtilsParserManager.java new file mode 100644 index 0000000000..08781911db --- /dev/null +++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/YangUtilsParserManager.java @@ -0,0 +1,110 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.yangutils.parser.impl; + +import org.antlr.v4.runtime.ANTLRFileStream; +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.onosproject.yangutils.datamodel.YangNode; +import org.onosproject.yangutils.parser.YangUtilsParser; +import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangLexer; +import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangParser; +import org.onosproject.yangutils.parser.exceptions.ParserException; +import org.onosproject.yangutils.parser.impl.parserutils.ParseTreeErrorListener; + +import java.io.IOException; + +/** + * Manages file parsing, parse tree creation and data model tree creation + * corresponding to an input YANG file. + */ +public class YangUtilsParserManager implements YangUtilsParser { + + @Override + public YangNode getDataModel(String yangFile) throws IOException, ParserException { + + /** + * Create a char stream that reads from YANG file. Throws an exception + * in case input YANG file is either null or non existent. + */ + ANTLRInputStream input = null; + try { + input = new ANTLRFileStream(yangFile); + } catch (IOException e) { + e.printStackTrace(); + throw e; + } + + // Create a lexer that feeds off of input char stream. + GeneratedYangLexer lexer = new GeneratedYangLexer(input); + + // Create a buffer of tokens pulled from the lexer. + CommonTokenStream tokens = new CommonTokenStream(lexer); + + // Create a parser that feeds off the tokens buffer. + GeneratedYangParser parser = new GeneratedYangParser(tokens); + + // Remove console error listener. + parser.removeErrorListeners(); + + // Create instance of customized error listener. + ParseTreeErrorListener parseTreeErrorListener = new ParseTreeErrorListener(); + + // Add customized error listener to catch errors during parsing. + parser.addErrorListener(parseTreeErrorListener); + + // Begin parsing YANG file and generate parse tree. + ParseTree tree = parser.yangfile(); + + /** + * Throws an parser Exception if exception flag is set i.e. exception has + * occurred during parsing. + */ + if (parseTreeErrorListener.isExceptionFlag()) { + // Get the exception occurred during parsing. + ParserException parserException = parseTreeErrorListener.getParserException(); + parserException.setFileName(yangFile); + throw parserException; + } + + // Create a walker to walk the parse tree. + ParseTreeWalker walker = new ParseTreeWalker(); + + // Create a listener implementation class object. + TreeWalkListener treeWalker = new TreeWalkListener(); + + /** + * Walk parse tree, provide call backs to methods in listener and + * build data model tree. + */ + walker.walk(treeWalker, tree); + + // Throws an parser exception which has occurred during listener walk. + if (treeWalker.getErrorInformation().isErrorFlag()) { + // Create object of listener exception + ParserException listenerException = new ParserException(); + listenerException.setMsg(treeWalker.getErrorInformation().getErrorMsg()); + listenerException.setFileName(yangFile); + throw listenerException; + } + + // Returns the Root Node of the constructed data model tree. + return treeWalker.getRootNode(); + } +} diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/parserutils/ListenerValidation.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/parserutils/ListenerValidation.java new file mode 100644 index 0000000000..6ecded3813 --- /dev/null +++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/parserutils/ListenerValidation.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.yangutils.parser.impl.parserutils; + +import org.onosproject.yangutils.parser.impl.TreeWalkListener; + +/** + * Its a utility to carry out listener validation. + */ +public final class ListenerValidation { + + /** + * Creates a new belongto listener. + */ + private ListenerValidation() { + } + + /** + * Checks if error is set or parsed data stack is empty. + * + * @param listener Listener's object. + * @param errNode parsable node for which validation needs to be done. + * @return validation result. + */ + public static boolean preValidation(TreeWalkListener listener, String errNode) { + + // Check whether error found while walking YANG file, if yes return true. + if (listener.getErrorInformation().isErrorFlag()) { + return true; + } + + // If stack is empty it indicates error condition + if (listener.getParsedDataStack().empty()) { + listener.getErrorInformation().setErrorFlag(true); + listener.getErrorInformation().setErrorMsg("Parsable stack empty at" + errNode + "entry"); + return true; + } + return false; + } +} \ No newline at end of file diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/parserutils/ParseTreeErrorListener.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/parserutils/ParseTreeErrorListener.java new file mode 100644 index 0000000000..d3926df37b --- /dev/null +++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/parserutils/ParseTreeErrorListener.java @@ -0,0 +1,65 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.yangutils.parser.impl.parserutils; + +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; +import org.onosproject.yangutils.parser.exceptions.ParserException; + +/** + * By default, ANTLR sends all errors to standard error, this is changed by + * providing this new implementation of interface ANTLRErrorListener. The + * interface has a syntaxError() method that applies to both lexer and + * parser. + */ +public class ParseTreeErrorListener extends BaseErrorListener { + + // Exception of type parser exceptions are catched during parsing. + private ParserException parserException = new ParserException(); + + // Flag to indicate presence of exception. + private boolean exceptionFlag = false; + + /** + * Returns the status of exception flag. + * + * @return flag which contains the status of exception. + */ + public boolean isExceptionFlag() { + return exceptionFlag; + } + + /** + * Returns the parser exception object populated with line, character + * position and message. + * + * @return object of parser exception. + */ + public ParserException getParserException() { + return parserException; + } + + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, + String msg, RecognitionException e) { + parserException.setLine(line); + parserException.setCharPosition(charPositionInLine); + parserException.setMsg(msg); + exceptionFlag = true; + } +} \ No newline at end of file diff --git a/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/impl/YangUtilsParserManagerTest.java b/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/impl/YangUtilsParserManagerTest.java new file mode 100644 index 0000000000..f8a61204ea --- /dev/null +++ b/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/impl/YangUtilsParserManagerTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.yangutils.parser.impl; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.yangutils.datamodel.YangNode; +import org.onosproject.yangutils.parser.exceptions.ParserException; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +/** + * Test case for testing YANG utils parser manager. + */ +public class YangUtilsParserManagerTest { + + YangUtilsParserManager manager = new YangUtilsParserManager(); + File file; + BufferedWriter out; + + @Before + public void setUp() throws Exception { + file = new File("demo.yang"); + out = new BufferedWriter(new FileWriter(file)); + } + @After + public void tearDown() throws Exception { + file.delete(); + } + + /** + * This test case checks whether the null pointer exception is generated + * when the input YANG file is null. + */ + @Test(expected = NullPointerException.class) + public void getDataModelNullFileTest() throws IOException, ParserException { + YangUtilsParserManager manager = new YangUtilsParserManager(); + YangNode node = manager.getDataModel(null); + } + + /** + * This test case checks whether the io exception is generated + * when the input YANG file is non existent. + */ + @Test(expected = IOException.class) + public void getDataModelNonExistentFileTest() throws IOException, ParserException { + + YangUtilsParserManager manager = new YangUtilsParserManager(); + YangNode node = manager.getDataModel("nonexistent.yang"); + } + + /** + * This test case checks if the input YANG file is correct no exception + * should be generated. + */ + @Test + public void getDataModelCorrectFileTest() throws IOException, ParserException { + + out.write("module ONOS {\n"); + out.write("yang-version 1;\n"); + out.write("namespace urn:ietf:params:xml:ns:yang:ietf-ospf;\n"); + out.write("prefix On;\n"); + out.write("}\n"); + out.close(); + + YangNode node = manager.getDataModel("demo.yang"); + } + + /** + * This test case checks if the input YANG file with wrong YANG constructs + * than parser exception should be generated. + */ + @Test(expected = ParserException.class) + public void getDataModelIncorrectFileTest() throws IOException, ParserException { + + out.write("module ONOS {\n"); + out.write("yang-version 1\n"); + out.write("namespace urn:ietf:params:xml:ns:yang:ietf-ospf;\n"); + out.write("prefix On;\n"); + out.write("}\n"); + out.close(); + + YangNode node = manager.getDataModel("demo.yang"); + } +} \ No newline at end of file diff --git a/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/parseutils/ListenerValidationTest.java b/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/parseutils/ListenerValidationTest.java new file mode 100644 index 0000000000..c047f2b33a --- /dev/null +++ b/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/parseutils/ListenerValidationTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.yangutils.parser.parseutils; + +import org.junit.Test; +import org.onosproject.yangutils.datamodel.YangRevision; +import org.onosproject.yangutils.parser.impl.TreeWalkListener; +import org.onosproject.yangutils.parser.impl.parserutils.ListenerError; +import org.onosproject.yangutils.parser.impl.parserutils.ListenerValidation; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + * Test case for testing listener validation util. + */ +public class ListenerValidationTest { + + /** + * This test case checks in case error pre-exists, listener validate + * function returns true. + */ + @Test + public void listenerValidationErrorExists() { + + // Create an test error. + ListenerError testError = new ListenerError(); + testError.setErrorFlag(true); + testError.setErrorMsg("Test Error"); + + // Create test walker and assign test error to it. + TreeWalkListener testWalker = new TreeWalkListener(); + testWalker.setErrorInformation(testError); + + // Create a temporary node of parsable. + YangRevision tmpNode = new YangRevision(); + testWalker.getParsedDataStack().push(tmpNode); + + boolean errorFlag = ListenerValidation.preValidation(testWalker, "ErrorTest"); + + /** + * Check for the values set in syntax error function. If not set properly + * report an assert. + */ + assertThat(errorFlag, is(true)); + } + + /** + * This test case checks in case parsable stack is empty, listener validate + * function returns true. + */ + @Test + public void listenerValidationEmptyStack() { + + // Create test walker and assign test error to it. + TreeWalkListener testWalker = new TreeWalkListener(); + + boolean errorFlag = ListenerValidation.preValidation(testWalker, "ErrorTest"); + + /** + * Check for the values set in syntax error function. If not set properly + * report an assert. + */ + assertThat(errorFlag, is(true)); + } + + /** + * This test case checks in case of error doesn't pre-exists and stack is, + * non empty, listener validate function returns false. + */ + @Test + public void listenerValidationNoErrorNotExists() { + + // Create test walker and assign test error to it. + TreeWalkListener testWalker = new TreeWalkListener(); + + // Create a temporary node of parsable. + YangRevision tmpNode = new YangRevision(); + testWalker.getParsedDataStack().push(tmpNode); + + boolean errorFlag = ListenerValidation.preValidation(testWalker, "ErrorTest"); + + /** + * Check for the values set in syntax error function. If not set properly + * report an assert. + */ + assertThat(errorFlag, is(false)); + } +} \ No newline at end of file diff --git a/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/parseutils/ParseTreeErrorListenerTest.java b/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/parseutils/ParseTreeErrorListenerTest.java new file mode 100644 index 0000000000..f91797ec7f --- /dev/null +++ b/utils/yangutils/src/test/java/org/onosproject/yangutils/parser/parseutils/ParseTreeErrorListenerTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.yangutils.parser.impl.parseutils; + +import org.antlr.v4.runtime.ANTLRFileStream; +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangLexer; +import org.onosproject.yangutils.parser.antlrgencode.GeneratedYangParser; +import org.onosproject.yangutils.parser.exceptions.ParserException; +import org.onosproject.yangutils.parser.impl.YangUtilsParserManager; +import org.onosproject.yangutils.parser.impl.parserutils.ParseTreeErrorListener; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + * Test case for testing parse tree error listener. + */ +public class ParseTreeErrorListenerTest { + + YangUtilsParserManager manager = new YangUtilsParserManager(); + File file; + BufferedWriter out; + + @Before + public void setUp() throws Exception { + file = new File("demo.yang"); + out = new BufferedWriter(new FileWriter(file)); + } + @After + public void tearDown() throws Exception { + file.delete(); + } + + /** + * This test case checks whether the error received from parser is correctly + * handled. + */ + @Test + public void syntaxErrorValidationTest() throws IOException { + + out.write("module ONOS {\n"); + out.write("yang-version 1\n"); + out.write("namespace urn:ietf:params:xml:ns:yang:ietf-ospf;\n"); + out.write("prefix On;\n"); + out.write("}\n"); + out.close(); + + ANTLRInputStream input = new ANTLRFileStream("demo.yang"); + + // Create a lexer that feeds off of input char stream. + GeneratedYangLexer lexer = new GeneratedYangLexer(input); + // Create a buffer of tokens pulled from the lexer. + CommonTokenStream tokens = new CommonTokenStream(lexer); + // Create a parser that feeds off the tokens buffer. + GeneratedYangParser parser = new GeneratedYangParser(tokens); + // Remove console error listener. + parser.removeErrorListeners(); + // Create instance of customized error listener. + ParseTreeErrorListener parseTreeErrorListener = new ParseTreeErrorListener(); + // Add customized error listener to catch errors during parsing. + parser.addErrorListener(parseTreeErrorListener); + // Begin parsing YANG file and generate parse tree. + ParseTree tree = parser.yangfile(); + // Get the exception occurred during parsing. + ParserException parserException = parseTreeErrorListener.getParserException(); + + /** + * Check for the values set in syntax error function. If not set properly + * report an assert. + */ + assertThat(parseTreeErrorListener.isExceptionFlag(), is(true)); + assertThat(parserException.getLineNumber(), is(3)); + assertThat(parserException.getCharPositionInLine(), is(0)); + } +} \ No newline at end of file