From 196131a66b309559ae4dde07067ec1ecbfb5ff47 Mon Sep 17 00:00:00 2001 From: "Valeriano A.R" Date: Wed, 25 Nov 2020 21:58:28 +0100 Subject: [PATCH] Custom Exceptions + Tests. --- VAR.ExpressionEvaluator.Tests/ParserTests.cs | 188 ++++++++++++++++++- VAR.ExpressionEvaluator/Parser.cs | 67 +++++-- 2 files changed, 241 insertions(+), 14 deletions(-) diff --git a/VAR.ExpressionEvaluator.Tests/ParserTests.cs b/VAR.ExpressionEvaluator.Tests/ParserTests.cs index de3381c..50532dd 100644 --- a/VAR.ExpressionEvaluator.Tests/ParserTests.cs +++ b/VAR.ExpressionEvaluator.Tests/ParserTests.cs @@ -204,7 +204,7 @@ namespace VAR.ExpressionEvaluator.Tests #endregion Variables - #region Funcitions + #region Functions [TestMethod()] public void Functions__MaxFunction() @@ -581,5 +581,191 @@ namespace VAR.ExpressionEvaluator.Tests } #endregion + + #region Excepctions + + [TestMethod()] + public void Exceptions__HelloAtEnd__UnexpectedCharactersAtEndException() + { + try + { + string expression = "1 + 1 \"Hello\""; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.UnexpectedCharactersAtEndException)); + } + } + + [TestMethod()] + public void Exceptions__TrueAtEndInsideParens__MissingCloseParenthesisException() + { + try + { + string expression = "(1+1 true)"; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.MissingCloseParenthesisException)); + } + } + + [TestMethod()] + public void Exceptions__TrueAtEndInsideFunctionCall__MissingCloseParenthesisException() + { + try + { + string expression = "Func(1 true)"; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.MissingCloseParenthesisException)); + } + } + + + [TestMethod()] + public void Exceptions__EOF__UnexpectedEOFException() + { + try + { + string expression = ""; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.UnexpectedEOFException)); + } + } + + [TestMethod()] + public void Exceptions__Plus__UnexpectedEOFException() + { + try + { + string expression = "+"; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.UnexpectedEOFException)); + } + } + + [TestMethod()] + public void Exceptions__Minus__UnexpectedEOFException() + { + try + { + string expression = "-"; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.UnexpectedEOFException)); + } + } + + [TestMethod()] + public void Exceptions__OpenParens__UnexpectedEOFException() + { + try + { + string expression = "("; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.UnexpectedEOFException)); + } + } + + [TestMethod()] + public void Exceptions__Comma__UnexpectedTokenException() + { + try + { + string expression = ","; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.UnexpectedTokenException)); + } + } + + [TestMethod()] + public void Exceptions__Division__UnexpectedTokenException() + { + try + { + string expression = "/"; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.UnexpectedTokenException)); + } + } + + [TestMethod()] + public void Exceptions__Multiply__UnexpectedTokenException() + { + try + { + string expression = "*"; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.UnexpectedTokenException)); + } + } + + [TestMethod()] + public void Exceptions__CloseParens__UnexpectedTokenException() + { + try + { + string expression = ")"; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.UnexpectedTokenException)); + } + } + + [TestMethod()] + public void Exceptions__Parens__UnexpectedTokenException() + { + try + { + string expression = "()"; + object result = Parser.EvaluateString(expression); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.IsInstanceOfType(ex, typeof(Parser.UnexpectedTokenException)); + } + } + + + #endregion Misc } } \ No newline at end of file diff --git a/VAR.ExpressionEvaluator/Parser.cs b/VAR.ExpressionEvaluator/Parser.cs index d6da62e..6934842 100644 --- a/VAR.ExpressionEvaluator/Parser.cs +++ b/VAR.ExpressionEvaluator/Parser.cs @@ -6,6 +6,32 @@ namespace VAR.ExpressionEvaluator { public class Parser { + #region Custom exceptions + + public class UnexpectedCharactersAtEndException : Exception + { + public UnexpectedCharactersAtEndException() : base("Unexpected characters at end of expression") { } + } + + public class MissingCloseParenthesisException : Exception + { + public MissingCloseParenthesisException() : base("Missing close parenthesis") { } + } + + public class UnexpectedEOFException : Exception + { + public UnexpectedEOFException() : base("Unexpected EOF") { } + } + + public class UnexpectedTokenException : Exception + { + public UnexpectedTokenException(string token) : base(string.Format("Unexpected token: {0}", token)) { } + } + + #endregion Custom exceptions + + #region Creator + private ITokenizer _tokenizer; public Parser(ITokenizer tokenizer) @@ -13,17 +39,9 @@ namespace VAR.ExpressionEvaluator _tokenizer = tokenizer; } - public IExpressionNode ParseExpression() - { - var expr = ParseBooleanOp(); + #endregion Creator - if (_tokenizer.Token != Token.EOF) - { - throw new Exception("Unexpected characters at end of expression"); - } - - return expr; - } + #region Parsing methods private IExpressionNode ParseBooleanOp() { @@ -226,7 +244,7 @@ namespace VAR.ExpressionEvaluator } if (_tokenizer.Token != Token.ParenthesisEnd) { - throw new Exception("Missing close parenthesis"); + throw new MissingCloseParenthesisException(); } _tokenizer.NextToken(); @@ -241,13 +259,34 @@ namespace VAR.ExpressionEvaluator IExpressionNode node = ParseBooleanOp(); if (_tokenizer.Token != Token.ParenthesisEnd) { - throw new Exception("Missing close parenthesis"); + throw new MissingCloseParenthesisException(); } _tokenizer.NextToken(); return node; } - throw new Exception(string.Format("Unexpected token: {0}", _tokenizer.Token.ToString())); + if (_tokenizer.Token == Token.EOF) + { + throw new UnexpectedEOFException(); + } + + throw new UnexpectedTokenException(_tokenizer.Token.ToString()); + } + + #endregion Parsing methods + + #region Public API + + public IExpressionNode ParseExpression() + { + var expr = ParseBooleanOp(); + + if (_tokenizer.Token != Token.EOF) + { + throw new UnexpectedCharactersAtEndException(); + } + + return expr; } public static IExpressionNode ParseString(string str) @@ -263,5 +302,7 @@ namespace VAR.ExpressionEvaluator IExpressionNode node = ParseString(str); return node.Eval(evaluationContext); } + + #endregion Public API } }