| using System; |
| using System.Text; |
| using System.Collections.Generic; |
| using System.Linq; |
| using Microsoft.VisualStudio.TestTools.UnitTesting; |
| using OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy; |
| using Rhino.Mocks; |
| using OfficeOpenXml.FormulaParsing.ExpressionGraph; |
| using OfficeOpenXml.FormulaParsing.LexicalAnalysis; |
| using OfficeOpenXml.FormulaParsing.Excel.Operators; |
| using OfficeOpenXml.FormulaParsing; |
| |
| namespace EPPlusTest.FormulaParsing.ExpressionGraph |
| { |
| [TestClass] |
| public class ExpressionGraphBuilderTests |
| { |
| private IExpressionGraphBuilder _graphBuilder; |
| private ExcelDataProvider _excelDataProvider; |
| |
| [TestInitialize] |
| public void Setup() |
| { |
| _excelDataProvider = MockRepository.GenerateStub<ExcelDataProvider>(); |
| var parsingContext = ParsingContext.Create(); |
| _graphBuilder = new ExpressionGraphBuilder(_excelDataProvider, parsingContext); |
| } |
| |
| [TestCleanup] |
| public void Cleanup() |
| { |
| |
| } |
| |
| [TestMethod] |
| public void BuildShouldNotUseStringIdentifyersWhenBuildingStringExpression() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("'", TokenType.String), |
| new Token("abc", TokenType.StringContent), |
| new Token("'", TokenType.String) |
| }; |
| |
| var result = _graphBuilder.Build(tokens); |
| |
| Assert.AreEqual(1, result.Expressions.Count()); |
| } |
| |
| [TestMethod] |
| public void BuildShouldNotEvaluateExpressionsWithinAString() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("'", TokenType.String), |
| new Token("1 + 2", TokenType.StringContent), |
| new Token("'", TokenType.String) |
| }; |
| |
| var result = _graphBuilder.Build(tokens); |
| |
| Assert.AreEqual("1 + 2", result.Expressions.First().Compile().Result); |
| } |
| |
| [TestMethod] |
| public void BuildShouldSetOperatorOnGroupExpressionCorrectly() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("(", TokenType.OpeningParenthesis), |
| new Token("2", TokenType.Integer), |
| new Token("+", TokenType.Operator), |
| new Token("4", TokenType.Integer), |
| new Token(")", TokenType.ClosingParenthesis), |
| new Token("*", TokenType.Operator), |
| new Token("2", TokenType.Integer) |
| }; |
| var result = _graphBuilder.Build(tokens); |
| |
| Assert.AreEqual(Operator.Multiply.Operator, result.Expressions.First().Operator.Operator); |
| |
| } |
| |
| [TestMethod] |
| public void BuildShouldSetChildrenOnGroupExpression() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("(", TokenType.OpeningParenthesis), |
| new Token("2", TokenType.Integer), |
| new Token("+", TokenType.Operator), |
| new Token("4", TokenType.Integer), |
| new Token(")", TokenType.ClosingParenthesis), |
| new Token("*", TokenType.Operator), |
| new Token("2", TokenType.Integer) |
| }; |
| var result = _graphBuilder.Build(tokens); |
| |
| Assert.IsInstanceOfType(result.Expressions.First(), typeof(GroupExpression)); |
| Assert.AreEqual(2, result.Expressions.First().Children.Count()); |
| } |
| |
| [TestMethod] |
| public void BuildShouldSetNextOnGroupedExpression() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("(", TokenType.OpeningParenthesis), |
| new Token("2", TokenType.Integer), |
| new Token("+", TokenType.Operator), |
| new Token("4", TokenType.Integer), |
| new Token(")", TokenType.ClosingParenthesis), |
| new Token("*", TokenType.Operator), |
| new Token("2", TokenType.Integer) |
| }; |
| var result = _graphBuilder.Build(tokens); |
| |
| Assert.IsNotNull(result.Expressions.First().Next); |
| Assert.IsInstanceOfType(result.Expressions.First().Next, typeof(IntegerExpression)); |
| |
| } |
| |
| [TestMethod] |
| public void BuildShouldBuildFunctionExpressionIfFirstTokenIsFunction() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("CStr", TokenType.Function), |
| new Token("(", TokenType.OpeningParenthesis), |
| new Token("2", TokenType.Integer), |
| new Token(")", TokenType.ClosingParenthesis), |
| }; |
| var result = _graphBuilder.Build(tokens); |
| |
| Assert.AreEqual(1, result.Expressions.Count()); |
| Assert.IsInstanceOfType(result.Expressions.First(), typeof(FunctionExpression)); |
| } |
| |
| [TestMethod] |
| public void BuildShouldSetChildrenOnFunctionExpression() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("CStr", TokenType.Function), |
| new Token("(", TokenType.OpeningParenthesis), |
| new Token("2", TokenType.Integer), |
| new Token(")", TokenType.ClosingParenthesis) |
| }; |
| var result = _graphBuilder.Build(tokens); |
| |
| Assert.AreEqual(1, result.Expressions.First().Children.Count()); |
| Assert.IsInstanceOfType(result.Expressions.First().Children.First(), typeof(GroupExpression)); |
| Assert.IsInstanceOfType(result.Expressions.First().Children.First().Children.First(), typeof(IntegerExpression)); |
| Assert.AreEqual(2d, result.Expressions.First().Children.First().Compile().Result); |
| } |
| |
| [TestMethod] |
| public void BuildShouldAddOperatorToFunctionExpression() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("CStr", TokenType.Function), |
| new Token("(", TokenType.OpeningParenthesis), |
| new Token("2", TokenType.Integer), |
| new Token(")", TokenType.ClosingParenthesis), |
| new Token("&", TokenType.Operator), |
| new Token("A", TokenType.StringContent) |
| }; |
| var result = _graphBuilder.Build(tokens); |
| |
| Assert.AreEqual(1, result.Expressions.First().Children.Count()); |
| Assert.AreEqual(2, result.Expressions.Count()); |
| } |
| |
| [TestMethod] |
| public void BuildShouldAddCommaSeparatedFunctionArgumentsAsChildrenToFunctionExpression() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("Text", TokenType.Function), |
| new Token("(", TokenType.OpeningParenthesis), |
| new Token("2", TokenType.Integer), |
| new Token(",", TokenType.Comma), |
| new Token("3", TokenType.Integer), |
| new Token(")", TokenType.ClosingParenthesis), |
| new Token("&", TokenType.Operator), |
| new Token("A", TokenType.StringContent) |
| }; |
| |
| var result = _graphBuilder.Build(tokens); |
| |
| Assert.AreEqual(2, result.Expressions.First().Children.Count()); |
| } |
| |
| [TestMethod] |
| public void BuildShouldCreateASingleExpressionOutOfANegatorAndANumericToken() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("-", TokenType.Negator), |
| new Token("2", TokenType.Integer), |
| }; |
| |
| var result = _graphBuilder.Build(tokens); |
| |
| Assert.AreEqual(1, result.Expressions.Count()); |
| Assert.AreEqual(-2d, result.Expressions.First().Compile().Result); |
| } |
| |
| [TestMethod] |
| public void BuildShouldHandleEnumerableTokens() |
| { |
| var tokens = new List<Token> |
| { |
| new Token("Text", TokenType.Function), |
| new Token("(", TokenType.OpeningParenthesis), |
| new Token("{", TokenType.OpeningEnumerable), |
| new Token("2", TokenType.Integer), |
| new Token(",", TokenType.Comma), |
| new Token("3", TokenType.Integer), |
| new Token("}", TokenType.ClosingEnumerable), |
| new Token(")", TokenType.ClosingParenthesis) |
| }; |
| |
| var result = _graphBuilder.Build(tokens); |
| var funcArgExpression = result.Expressions.First().Children.First(); |
| Assert.IsInstanceOfType(funcArgExpression, typeof(FunctionArgumentExpression)); |
| |
| var enumerableExpression = funcArgExpression.Children.First(); |
| |
| Assert.IsInstanceOfType(enumerableExpression, typeof(EnumerableExpression)); |
| Assert.AreEqual(2, enumerableExpression.Children.Count(), "Enumerable.Count was not 2"); |
| } |
| |
| [TestMethod] |
| public void ShouldHandleInnerFunctionCall2() |
| { |
| var ctx = ParsingContext.Create(); |
| const string formula = "IF(3>2;\"Yes\";\"No\")"; |
| var tokenizer = new SourceCodeTokenizer(ctx.Configuration.FunctionRepository, ctx.NameValueProvider); |
| var tokens = tokenizer.Tokenize(formula); |
| var expression = _graphBuilder.Build(tokens); |
| Assert.AreEqual(1, expression.Expressions.Count()); |
| |
| var compiler = new ExpressionCompiler(new ExpressionConverter(), new CompileStrategyFactory()); |
| var result = compiler.Compile(expression.Expressions); |
| Assert.AreEqual("Yes", result.Result); |
| } |
| |
| [TestMethod] |
| public void ShouldHandleInnerFunctionCall3() |
| { |
| var ctx = ParsingContext.Create(); |
| const string formula = "IF(I10>=0;IF(O10>I10;((O10-I10)*$B10)/$C$27;IF(O10<0;(O10*$B10)/$C$27;\"\"));IF(O10<0;((O10-I10)*$B10)/$C$27;IF(O10>0;(O10*$B10)/$C$27;)))"; |
| var tokenizer = new SourceCodeTokenizer(ctx.Configuration.FunctionRepository, ctx.NameValueProvider); |
| var tokens = tokenizer.Tokenize(formula); |
| var expression = _graphBuilder.Build(tokens); |
| Assert.AreEqual(1, expression.Expressions.Count()); |
| var exp1 = expression.Expressions.First(); |
| Assert.AreEqual(3, exp1.Children.Count()); |
| } |
| [TestMethod] |
| public void RemoveDuplicateOperators1() |
| { |
| var ctx = ParsingContext.Create(); |
| const string formula = "++1--2++-3+-1----3-+2"; |
| var tokenizer = new SourceCodeTokenizer(ctx.Configuration.FunctionRepository, ctx.NameValueProvider); |
| var tokens = tokenizer.Tokenize(formula).ToList(); |
| var expression = _graphBuilder.Build(tokens); |
| Assert.AreEqual(11, tokens.Count()); |
| Assert.AreEqual("+", tokens[1].Value); |
| Assert.AreEqual("-", tokens[3].Value); |
| Assert.AreEqual("-", tokens[5].Value); |
| Assert.AreEqual("+", tokens[7].Value); |
| Assert.AreEqual("-", tokens[9].Value); |
| } |
| [TestMethod] |
| public void RemoveDuplicateOperators2() |
| { |
| var ctx = ParsingContext.Create(); |
| const string formula = "++-1--(---2)++-3+-1----3-+2"; |
| var tokenizer = new SourceCodeTokenizer(ctx.Configuration.FunctionRepository, ctx.NameValueProvider); |
| var tokens = tokenizer.Tokenize(formula).ToList(); |
| } |
| } |
| } |