blob: 2a40ab899cfbe156a50f313381acd6a952448c23 [file] [log] [blame]
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();
}
}
}