test: fix SqlBreakdown tests project
SonarQube Analysis / sonarqube (push) Failing after 3m21s

This commit is contained in:
Thom Lamb
2026-05-15 13:39:14 -05:00
parent 79879c62b4
commit 8b0368e810
30 changed files with 21 additions and 3 deletions
@@ -0,0 +1,117 @@
using Strata.SqlTools.SqlBreakdown.Classes;
using Strata.SqlTools.SqlBreakdown.Expressions;
using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Aggregate;
using Strata.SqlTools.SqlBreakdown.Expressions.Literals;
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
[TestFixture]
public class ArithmeticExpressionTests : ExpressionTestsBase
{
private static IEnumerable<TestCaseData> ArithmeticExpressionTestCases()
{
var testCases = new[]
{
new ExpressionTestCase
{
Name = "WithSum_{m}",
Arrange = new Dictionary<string, Expression>
{
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES")),
["cost"] = new RegisteredTableColumnExpression(3, "COST", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
},
Act = (columns, visitor) =>
{
var revenue = columns["revenue"];
var cost = columns["cost"];
var addExp = new SumFunction(revenue - cost - 1001);
return addExp.Accept(visitor);
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Does.Contain("SUM"));
Assert.That(sql, Does.Contain("-"));
Assert.That(sql, Does.Contain("1001"));
Assert.That(sql, Is.EqualTo("SUM(PES.NET_REVENUE - PES.COST - 1001)"));
return true;
}
},
new ExpressionTestCase
{
Name = "Addition_{m}",
Arrange = new Dictionary<string, Expression>
{
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
},
Act = (columns, visitor) =>
{
var revenue = columns["revenue"];
var result = revenue + new NumberLiteralExpression(1000);
return result.Accept(visitor);
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Does.Contain("NET_REVENUE"));
Assert.That(sql, Does.Contain("+"));
Assert.That(sql, Does.Contain("1000"));
return true;
}
},
new ExpressionTestCase
{
Name = "Multiplication_{m}",
Arrange = new Dictionary<string, Expression>
{
["cost"] = new RegisteredTableColumnExpression(3, "COST", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
},
Act = (columns, visitor) =>
{
var cost = columns["cost"];
var result = cost * new NumberLiteralExpression(1.5m);
return result.Accept(visitor);
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Does.Contain("COST"));
Assert.That(sql, Does.Contain("*"));
Assert.That(sql, Does.Contain("1.5"));
return true;
}
},
new ExpressionTestCase
{
Name = "Division_{m}",
Arrange = new Dictionary<string, Expression>
{
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
},
Act = (columns, visitor) =>
{
var revenue = columns["revenue"];
var result = revenue / new NumberLiteralExpression(2);
return result.Accept(visitor);
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Does.Contain("NET_REVENUE"));
Assert.That(sql, Does.Contain("/"));
Assert.That(sql, Does.Contain("2"));
return true;
}
}
};
foreach (var testCase in testCases)
{
yield return new TestCaseData(testCase).SetName(testCase.Name);
}
}
[TestCaseSource(nameof(ArithmeticExpressionTestCases))]
public void ArithmeticExpression_GeneratesCorrectSql(ExpressionTestCase testCase)
=> ExecuteExpressionTest(testCase);
}
@@ -0,0 +1,134 @@
using Strata.SqlTools.SqlBreakdown.Classes;
using Strata.SqlTools.SqlBreakdown.Expressions;
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional;
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Comparisons;
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Logical;
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
[TestFixture]
public class BooleanExpressionTests : ExpressionTestsBase
{
[Test]
public void BooleanExpression_AndOperator_ChainsCorrectly()
{
// Arrange
var greaterThan250Exp = new GreaterThanExpression(_costColumnExp, 250);
BooleanExpression original = BooleanExpression.False;
// Act
original &= greaterThan250Exp;
var firstResult = original;
original &= greaterThan250Exp;
var secondResult = original;
// Assert
Assert.That(firstResult, Is.Not.SameAs(BooleanExpression.False));
Assert.That(firstResult, Is.AssignableTo<BooleanExpression>());
Assert.That(secondResult, Is.Not.SameAs(BooleanExpression.False));
Assert.That(secondResult, Is.TypeOf<AndExpression>());
}
[Test]
public void BooleanExpression_ComplexWithOperators_CreatesExpression()
{
// Arrange
var paramFoobar = new ParameterExpression("FOOBAR");
// Act
#pragma warning disable S2178 // Short-circuit logic should be used in boolean contexts
var andComp = _revenueColumnExp > 100 & _costColumnExp >= 250 | _nameColumnExp == paramFoobar;
#pragma warning restore S2178
// Assert
Assert.That(andComp, Is.Not.Null);
Assert.That(andComp, Is.AssignableTo<BooleanExpression>());
}
private static IEnumerable<TestCaseData> BooleanExpressionTestCases()
{
var testCases = new[]
{
new ExpressionTestCase
{
Name = "GreaterThan_{m}",
Arrange = new Dictionary<string, Expression>
{
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
},
Act = (columns, visitor) =>
{
var revenue = columns["revenue"];
var greaterThan100Exp = new GreaterThanExpression(revenue, 100);
return greaterThan100Exp;
},
Assertions = result =>
{
var expression = (BooleanExpression)result;
Assert.That(expression, Is.Not.Null);
Assert.That(expression, Is.TypeOf<GreaterThanExpression>());
return true;
}
},
new ExpressionTestCase
{
Name = "And_{m}",
Arrange = new Dictionary<string, Expression>
{
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES")),
["cost"] = new RegisteredTableColumnExpression(3, "COST", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
},
Act = (columns, visitor) =>
{
var revenue = columns["revenue"];
var cost = columns["cost"];
var greaterThan100Exp = new GreaterThanExpression(revenue, 100);
var greaterThan250Exp = new GreaterThanExpression(cost, 250);
var andExp1 = new AndExpression(greaterThan100Exp, greaterThan250Exp);
return andExp1;
},
Assertions = result =>
{
var expression = (BooleanExpression)result;
Assert.That(expression, Is.Not.Null);
Assert.That(expression, Is.TypeOf<AndExpression>());
return true;
}
},
new ExpressionTestCase
{
Name = "Or_{m}",
Arrange = new Dictionary<string, Expression>
{
["revenue"] = new RegisteredTableColumnExpression(2, "NET_REVENUE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES")),
["cost"] = new RegisteredTableColumnExpression(3, "COST", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
},
Act = (columns, visitor) =>
{
var revenue = columns["revenue"];
var cost = columns["cost"];
#pragma warning disable S2178 // Short-circuit logic should be used in boolean contexts
var orComp = revenue > 100 | cost >= 250;
#pragma warning restore S2178
return orComp;
},
Assertions = result =>
{
var expression = (BooleanExpression)result;
Assert.That(expression, Is.Not.Null);
Assert.That(expression, Is.AssignableTo<BooleanExpression>());
return true;
}
}
};
foreach (var testCase in testCases)
{
yield return new TestCaseData(testCase).SetName(testCase.Name);
}
}
[TestCaseSource(nameof(BooleanExpressionTestCases))]
public void BooleanExpression_GeneratesCorrectExpression(ExpressionTestCase testCase)
=> ExecuteExpressionTest(testCase);
}
@@ -0,0 +1,117 @@
using Strata.SqlTools.SqlBreakdown.Classes;
using Strata.SqlTools.SqlBreakdown.Expressions;
using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Aggregate;
using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Conditional;
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
[TestFixture]
public class ConditionalExpressionTests : ExpressionTestsBase
{
private static IEnumerable<TestCaseData> ConditionalExpressionTestCases()
{
var testCases = new[]
{
new ExpressionTestCase
{
Name = "CaseExpression_{m}",
Arrange = new Dictionary<string, Expression>(),
Act = (columns, visitor) =>
{
var table = new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES");
var nameCol = new RegisteredTableColumnExpression(1, "DEPARTMENT_NAME", table);
var revenueCol = new RegisteredTableColumnExpression(2, "NET_REVENUE", table);
var caseExp = new CaseExpression(nameCol == "department 1", revenueCol, 0);
return caseExp.Accept(visitor);
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Does.Contain("CASE"));
Assert.That(sql, Does.Contain("WHEN"));
Assert.That(sql, Does.Contain("THEN"));
Assert.That(sql, Does.Contain("ELSE"));
Assert.That(sql, Does.Contain("END"));
return true;
}
},
new ExpressionTestCase
{
Name = "CaseExpressionWithSum_{m}",
Arrange = new Dictionary<string, Expression>(),
Act = (columns, visitor) =>
{
var table = new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES");
var nameCol = new RegisteredTableColumnExpression(1, "DEPARTMENT_NAME", table);
var revenueCol = new RegisteredTableColumnExpression(2, "NET_REVENUE", table);
var caseExp = new CaseExpression(nameCol == "department 1", revenueCol, 0);
var sumCaseExp = new SumFunction(caseExp);
return sumCaseExp.Accept(visitor);
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Does.Contain("SUM"));
Assert.That(sql, Does.Contain("CASE"));
Assert.That(sql, Does.Contain("WHEN"));
Assert.That(sql, Is.EqualTo("SUM(CASE\n WHEN PES.DEPARTMENT_NAME = 'department 1' THEN PES.NET_REVENUE\n ELSE 0\nEND)"));
return true;
}
},
new ExpressionTestCase
{
Name = "CaseExpressionWithSumInSelectColumn_{m}",
Arrange = new Dictionary<string, Expression>(),
Act = (columns, visitor) =>
{
var table = new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES");
var nameCol = new RegisteredTableColumnExpression(1, "DEPARTMENT_NAME", table);
var revenueCol = new RegisteredTableColumnExpression(2, "NET_REVENUE", table);
var caseExp = new CaseExpression(nameCol == "department 1", revenueCol, 0);
var sumCaseExp = new SumFunction(caseExp);
var column = new SelectClauseColumn(sumCaseExp, "mySumCaseCol");
return column.Accept(visitor);
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Does.Contain("SUM"));
Assert.That(sql, Does.Contain("CASE"));
Assert.That(sql, Does.Contain("mySumCaseCol"));
Assert.That(sql, Is.EqualTo("SUM(CASE\n WHEN PES.DEPARTMENT_NAME = 'department 1' THEN PES.NET_REVENUE\n ELSE 0\nEND) AS mySumCaseCol"));
return true;
}
},
new ExpressionTestCase
{
Name = "IfThenElseExpression_{m}",
Arrange = new Dictionary<string, Expression>(),
Act = (columns, visitor) =>
{
var table = new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES");
var nameCol = new RegisteredTableColumnExpression(1, "DEPARTMENT_NAME", table);
var revenueCol = new RegisteredTableColumnExpression(2, "NET_REVENUE", table);
var costCol = new RegisteredTableColumnExpression(3, "COST", table);
var ifElseExp = new IfThenElseExpression(nameCol == "myDeptName", revenueCol, costCol);
return ifElseExp.Accept(visitor);
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Does.Contain("IFF"));
Assert.That(sql, Is.EqualTo("IFF(PES.DEPARTMENT_NAME = 'myDeptName', PES.NET_REVENUE, PES.COST)"));
return true;
}
}
};
foreach (var testCase in testCases)
{
yield return new TestCaseData(testCase).SetName(testCase.Name);
}
}
[TestCaseSource(nameof(ConditionalExpressionTestCases))]
public void ConditionalExpression_GeneratesCorrectSql(ExpressionTestCase testCase)
=> ExecuteExpressionTest(testCase);
}
@@ -0,0 +1,46 @@
using Strata.SqlTools.SqlBreakdown.Classes;
using Strata.SqlTools.SqlBreakdown.Expressions;
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
[TestFixture]
public class DateFunctionTests : ExpressionTestsBase
{
private static IEnumerable<TestCaseData> DateFunctionTestCases()
{
var testCases = new[]
{
new ExpressionTestCase
{
Name = "GetFiscalYearMonthExpression_{m}",
Arrange = new Dictionary<string, Expression>
{
["dischargeDate"] = new RegisteredTableColumnExpression(4, "DISCHARGE_DATE", new RegisteredTableSource(101, "CLIENT_DSS", "DEPT", "PES"))
},
Act = (columns, visitor) =>
{
var dischargeDate = columns["dischargeDate"];
var fiscal = TestExpressionFactory.GetFiscalYearMonthExpression(dischargeDate, 7, 1);
return fiscal.Accept(visitor);
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Is.Not.Null);
Assert.That(sql.Length, Is.GreaterThan(0));
Assert.That(sql, Is.EqualTo("DATE_TRUNC('month', DATEADD('month', 6, PES.DISCHARGE_DATE))"));
return true;
}
}
};
foreach (var testCase in testCases)
{
yield return new TestCaseData(testCase).SetName(testCase.Name);
}
}
[TestCaseSource(nameof(DateFunctionTestCases))]
public void DateFunction_GeneratesCorrectSql(ExpressionTestCase testCase)
=> ExecuteExpressionTest(testCase);
}
@@ -0,0 +1,54 @@
using Strata.SqlTools.SqlServer.ExpressionFactory.Query;
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
[TestFixture]
public class ExpressionFactoryFilterTests : ExpressionTestsBase
{
private static IEnumerable<TestCaseData> FilterTestCases()
{
var dischargeDate = DateTime.Now.Date.AddMonths(1);
var startOfCurrentMonth = new DateTime(dischargeDate.Year, dischargeDate.Month, 1);
var startOfEndMonth = startOfCurrentMonth.AddMonths(3);
yield return new TestCaseData(
new Filter(2, FilterType.List, new object[] { "foo", "bar", "baz", 1234 }, Array.Empty<FilterCondition>(), DatePart.Continuous, false, 0, 0),
"DEPT.NAME IN ('foo', 'bar', 'baz', 1234)"
).SetName("ListFilterContinuous_{m}");
yield return new TestCaseData(
new Filter(4, FilterType.List, new[] { "FY2019", "FY2020", "FY2021", "FY2022" }, Array.Empty<FilterCondition>(), DatePart.FiscalYear, false, 0, 0),
"(DEPT.DISCHARGE_DATE >= '2018-07-01' AND DEPT.DISCHARGE_DATE < '2019-07-01') OR \n(DEPT.DISCHARGE_DATE >= '2019-07-01' AND DEPT.DISCHARGE_DATE < '2020-07-01') OR \n(DEPT.DISCHARGE_DATE >= '2020-07-01' AND DEPT.DISCHARGE_DATE < '2021-07-01') OR \n(DEPT.DISCHARGE_DATE >= '2021-07-01' AND DEPT.DISCHARGE_DATE < '2022-07-01')"
).SetName("DateListFilterFiscalYear_{m}");
yield return new TestCaseData(
new Filter(4, FilterType.List, new[] { "01-2020" }, Array.Empty<FilterCondition>(), DatePart.Month, false, 0, 0),
"DEPT.DISCHARGE_DATE >= '2020-01-01' AND DEPT.DISCHARGE_DATE < '2020-02-01'"
).SetName("MonthListFilter_{m}");
yield return new TestCaseData(
new Filter(4, FilterType.Calendar, new[] { "01/01/2019", "01/01/2023" }, Array.Empty<FilterCondition>(), DatePart.Month, false, 0, 0),
"DEPT.DISCHARGE_DATE >= '2019-01-01' AND DEPT.DISCHARGE_DATE < '2023-01-01'"
).SetName("CalendarFilter_{m}");
yield return new TestCaseData(
new Filter(4, FilterType.Timeframe, new object[] { }, Array.Empty<FilterCondition>(), DatePart.Month, false, 1, 3),
$"DEPT.DISCHARGE_DATE >= '{startOfCurrentMonth:yyyy-MM-dd}' AND DEPT.DISCHARGE_DATE < '{startOfEndMonth:yyyy-MM-dd}'"
).SetName("TimeframeFilter_{m}");
}
[TestCaseSource(nameof(FilterTestCases))]
public void ExpressionFactory_Filter_GeneratesCorrectSql(Filter filter, string expectedSql)
{
// Arrange
var factory = new TestExpressionFactory();
// Act
var condition = factory.CreateBooleanExpression(filter);
var result = condition.Accept(_sqlVisitor);
// Assert
Assert.That(result, Is.Not.Null);
Assert.That(result.Length, Is.GreaterThan(0));
Assert.That(result, Is.EqualTo(expectedSql));
}
}
@@ -0,0 +1,72 @@
using Strata.SqlTools.SqlBreakdown.Expressions;
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional;
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Comparisons;
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
[TestFixture]
public class ExpressionObjectTests : ExpressionTestsBase
{
[Test]
public void RegisteredTableColumnExpression_CreatesWithProperties()
{
// Arrange & Act
var columnExp = new RegisteredTableColumnExpression(5, "TEST_COLUMN", _table);
// Assert
Assert.That(columnExp, Is.Not.Null);
Assert.That(columnExp.ColumnName, Is.EqualTo("TEST_COLUMN"));
}
[Test]
public void ParameterExpression_CreatesWithName()
{
// Arrange & Act
var paramExp = new ParameterExpression("MY_PARAM");
// Assert
Assert.That(paramExp, Is.Not.Null);
Assert.That(paramExp.ParameterName, Is.EqualTo("MY_PARAM"));
}
private static IEnumerable<TestCaseData> ComparisonExpressionTestCases()
{
yield return new TestCaseData("GreaterThanOrEqual", 250, typeof(GreaterThanOrEqualToExpression))
.SetName("GreaterThanOrEqual_{m}");
yield return new TestCaseData("LessThan", 1000, typeof(LessThanExpression))
.SetName("LessThan_{m}");
yield return new TestCaseData("Equals", "TestDept", typeof(EqualToExpression))
.SetName("Equals_{m}");
yield return new TestCaseData("NotIn", new[] { "value1", "value2", "value3" }, typeof(NotInExpression))
.SetName("NotIn_{m}");
yield return new TestCaseData("Like", "%pattern%", typeof(LikeExpression))
.SetName("Like_{m}");
yield return new TestCaseData("Between", new object[] { 0, 5000 }, typeof(BetweenExpression))
.SetName("Between_{m}");
}
[TestCaseSource(nameof(ComparisonExpressionTestCases))]
public void ComparisonExpression_CreatesExpression(string expressionType, object testValue, Type expectedType)
{
// Arrange & Act
BooleanExpression expression = expressionType switch
{
"GreaterThanOrEqual" => new GreaterThanOrEqualToExpression(_costColumnExp, (int)testValue),
"LessThan" => new LessThanExpression(_revenueColumnExp, (int)testValue),
"Equals" => new EqualToExpression(_nameColumnExp, (string)testValue),
"NotIn" => new NotInExpression(_nameColumnExp, ((string[])testValue).Select(v => (Expression)v).ToArray()),
"Like" => new LikeExpression(_nameColumnExp, (string)testValue),
"Between" => new BetweenExpression(_revenueColumnExp, (Expression)(int)((object[])testValue)[0], (Expression)(int)((object[])testValue)[1]),
_ => throw new ArgumentException($"Unknown expression type: {expressionType}")
};
// Assert
Assert.That(expression, Is.Not.Null);
Assert.That(expression, Is.TypeOf(expectedType));
}
}
@@ -0,0 +1,30 @@
using Strata.SqlTools.SqlBreakdown.Expressions;
using Strata.SqlTools.Visitors.Snowflake;
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
/// <summary>
/// Represents a test case for expression tests with arrange, act, and assert phases.
/// </summary>
public class ExpressionTestCase
{
/// <summary>
/// Gets or initializes the name of the test case.
/// </summary>
public string Name { get; init; } = string.Empty;
/// <summary>
/// Gets or initializes the dictionary of expressions to arrange for the test.
/// </summary>
public Dictionary<string, Expression> Arrange { get; init; } = new();
/// <summary>
/// Gets or initializes the action to execute during the act phase of the test.
/// </summary>
public Func<Dictionary<string, Expression>, CommandVisitor, object> Act { get; init; } = null!;
/// <summary>
/// Gets or initializes the function to execute during the assert phase of the test that returns true if all assertions pass.
/// </summary>
public Func<object, bool> Assertions { get; init; } = null!;
}
@@ -0,0 +1,72 @@
using Strata.SqlTools.SqlBreakdown.Classes;
using Strata.SqlTools.SqlBreakdown.Expressions;
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional;
using Strata.SqlTools.SqlServer.ExpressionFactory.Query;
using Strata.SqlTools.SqlBreakdown.Tests.RegisteredTables;
using Strata.SqlTools.Visitors.Snowflake;
using ExpressionFactoryBase = Strata.SqlTools.SqlServer.ExpressionFactory.ExpressionFactory;
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
/// <summary>
/// Test implementation of ExpressionFactory for unit testing.
/// Uses July 1 as the fiscal year start date.
/// </summary>
internal class TestExpressionFactory : ExpressionFactoryBase
{
protected override DateTime GetCurrentFiscalYearStart()
{
return new DateTime(DateTime.UtcNow.Year, 7, 1, 0, 0, 0, DateTimeKind.Utc);
}
protected override RegisteredTableColumnExpression GetColumnExpression(int dataColumnId)
{
return RegisteredTableColumns.GetColumn(dataColumnId);
}
// Public wrappers for testing protected methods
public new BooleanExpression CreateBooleanExpression(Filter filter) => base.CreateBooleanExpression(filter);
public static new Expression GetFiscalYearMonthExpression(Expression dateColumnExpr, int fiscalYearStartMonth, int fiscalYearStartDay)
=> ExpressionFactoryBase.GetFiscalYearMonthExpression(dateColumnExpr, fiscalYearStartMonth, fiscalYearStartDay);
}
/// <summary>
/// Base class for expression tests with common setup.
/// </summary>
public abstract class ExpressionTestsBase
{
protected RegisteredTableSource _table = null!;
protected RegisteredTableColumnExpression _nameColumnExp = null!;
protected RegisteredTableColumnExpression _revenueColumnExp = null!;
protected RegisteredTableColumnExpression _costColumnExp = null!;
protected RegisteredTableColumnExpression _dischargeDateColumnExp = null!;
protected CommandVisitor _sqlVisitor = null!;
[SetUp]
public void SetUp()
{
_table = new RegisteredTableSource(101, "CLIENT_DSS", "FACT_PATIENT_ENCOUNTER_SUMMARY", "PES");
_nameColumnExp = new RegisteredTableColumnExpression(1, "DEPARTMENT_NAME", _table);
_revenueColumnExp = new RegisteredTableColumnExpression(2, "NET_REVENUE", _table);
_costColumnExp = new RegisteredTableColumnExpression(3, "COST", _table);
_dischargeDateColumnExp = new RegisteredTableColumnExpression(4, "DISCHARGE_DATE", _table);
_sqlVisitor = new CommandVisitor();
}
/// <summary>
/// Executes an expression test case with arrange, act, and assert phases.
/// </summary>
/// <param name="testCase">The test case to execute.</param>
protected void ExecuteExpressionTest(ExpressionTestCase testCase)
{
// Arrange
var visitor = new CommandVisitor();
var arrange = testCase.Arrange;
// Act
var result = testCase.Act(arrange, visitor);
// Assert
Assert.That(testCase.Assertions(result));
}
}
@@ -0,0 +1,203 @@
using Strata.SqlTools.SqlBreakdown.Expressions;
using Strata.SqlTools.SqlBreakdown.Expressions.Literals;
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
[TestFixture]
public class GenericColumnExpressionTests : ExpressionTestsBase
{
private static IEnumerable<TestCaseData> GenericColumnExpressionTestCases()
{
var testCases = new[]
{
new ExpressionTestCase
{
Name = "WithArithmeticOperatorsAndLiterals_{m}",
Arrange = new Dictionary<string, Expression>
{
["price"] = new GenericColumnExpression("Price", "Products"),
["quantity"] = new GenericColumnExpression("Quantity", "Products")
},
Act = (columns, visitor) =>
{
var price = columns["price"];
var quantity = columns["quantity"];
var priceWithTax = price * new NumberLiteralExpression(1.1m);
var priceWithFee = price + new NumberLiteralExpression(10);
var revenue = quantity * price;
return new Dictionary<string, string>
{
["priceWithTax"] = priceWithTax.Accept(visitor),
["priceWithFee"] = priceWithFee.Accept(visitor),
["revenue"] = revenue.Accept(visitor)
};
},
Assertions = result =>
{
var results = (Dictionary<string, string>)result;
Assert.That(results["priceWithTax"], Does.Contain("Price"));
Assert.That(results["priceWithTax"], Does.Contain("1.1"));
Assert.That(results["priceWithFee"], Does.Contain("Price"));
Assert.That(results["priceWithFee"], Does.Contain("10"));
Assert.That(results["revenue"], Does.Contain("Quantity"));
Assert.That(results["revenue"], Does.Contain("Price"));
return true;
}
},
new ExpressionTestCase
{
Name = "WithComparisonOperators_{m}",
Arrange = new Dictionary<string, Expression>
{
["price"] = new GenericColumnExpression("Price", "Products"),
["category"] = new GenericColumnExpression("Category", "Products")
},
Act = (columns, visitor) =>
{
var price = columns["price"];
var category = columns["category"];
var priceCondition = price > 100;
var categoryCondition = category == "Electronics";
return new Dictionary<string, string>
{
["priceCondition"] = priceCondition.Accept(visitor),
["categoryCondition"] = categoryCondition.Accept(visitor)
};
},
Assertions = result =>
{
var results = (Dictionary<string, string>)result;
Assert.That(results["priceCondition"], Does.Contain("Price"));
Assert.That(results["priceCondition"], Does.Contain("100"));
Assert.That(results["categoryCondition"], Does.Contain("Category"));
Assert.That(results["categoryCondition"], Does.Contain("Electronics"));
return true;
}
},
new ExpressionTestCase
{
Name = "InQueryBreakdown_{m}",
Arrange = new Dictionary<string, Expression>
{
["productId"] = new GenericColumnExpression("ProductID", "Products"),
["price"] = new GenericColumnExpression("Price", "Products"),
["category"] = new GenericColumnExpression("Category", "Products")
},
Act = (columns, visitor) =>
{
var query = new Breakdowns.SqlServer.QueryBreakdown();
query.FromClause.Clause = "Products";
var productId = columns["productId"];
var price = columns["price"];
var category = columns["category"];
query.AddSelectExpression(productId, "ID");
query.AddSelectExpression(price * new NumberLiteralExpression(1.1m), "PriceWithTax");
query.AddSelectExpression(price + new NumberLiteralExpression(10), "PriceWithFee");
query.AddWhereExpression(price > 100);
query.AddWhereExpression(category == "Electronics", null, "AND");
return query.GetSql();
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Does.Contain("ProductID"));
Assert.That(sql, Does.Contain("Price"));
Assert.That(sql, Does.Contain("Category"));
Assert.That(sql, Does.Contain("Products"));
return true;
}
},
new ExpressionTestCase
{
Name = "ComplexArithmetic_{m}",
Arrange = new Dictionary<string, Expression>
{
["quantity"] = new GenericColumnExpression("Quantity", "OrderDetails"),
["unitPrice"] = new GenericColumnExpression("UnitPrice", "OrderDetails"),
["discount"] = new GenericColumnExpression("Discount", "OrderDetails")
},
Act = (columns, visitor) =>
{
var quantity = columns["quantity"];
var unitPrice = columns["unitPrice"];
var discount = columns["discount"];
var totalRevenue = (quantity * unitPrice) * (new NumberLiteralExpression(1) - discount);
return totalRevenue.Accept(visitor);
},
Assertions = result =>
{
var sql = (string)result;
Assert.That(sql, Does.Contain("Quantity"));
Assert.That(sql, Does.Contain("UnitPrice"));
Assert.That(sql, Does.Contain("Discount"));
return true;
}
},
new ExpressionTestCase
{
Name = "WithSchema_{m}",
Arrange = new Dictionary<string, Expression>
{
["customerId"] = new GenericColumnExpression("CustomerID", "dbo", "Customers"),
["orderDate"] = new GenericColumnExpression("OrderDate", "dbo", "Orders")
},
Act = (columns, visitor) =>
{
return new Dictionary<string, string>
{
["customerResult"] = columns["customerId"].Accept(visitor),
["orderResult"] = columns["orderDate"].Accept(visitor)
};
},
Assertions = result =>
{
var results = (Dictionary<string, string>)result;
Assert.That(results["customerResult"], Does.Contain("CustomerID"));
Assert.That(results["orderResult"], Does.Contain("OrderDate"));
return true;
}
},
new ExpressionTestCase
{
Name = "MultipleComparisonOperators_{m}",
Arrange = new Dictionary<string, Expression>
{
["unitPrice"] = new GenericColumnExpression("UnitPrice", "Products"),
["minPrice"] = new GenericColumnExpression("MinPrice", "PriceRanges"),
["maxPrice"] = new GenericColumnExpression("MaxPrice", "PriceRanges")
},
Act = (columns, visitor) =>
{
var unitPrice = columns["unitPrice"];
var minPrice = columns["minPrice"];
var maxPrice = columns["maxPrice"];
var lowerBound = unitPrice >= minPrice;
var upperBound = unitPrice <= maxPrice;
return new Dictionary<string, string>
{
["lowerBound"] = lowerBound.Accept(visitor),
["upperBound"] = upperBound.Accept(visitor)
};
},
Assertions = result =>
{
var results = (Dictionary<string, string>)result;
Assert.That(results["lowerBound"], Does.Contain("UnitPrice"));
Assert.That(results["lowerBound"], Does.Contain("MinPrice"));
Assert.That(results["upperBound"], Does.Contain("UnitPrice"));
Assert.That(results["upperBound"], Does.Contain("MaxPrice"));
return true;
}
}
};
foreach (var testCase in testCases)
{
yield return new TestCaseData(testCase).SetName(testCase.Name);
}
}
[TestCaseSource(nameof(GenericColumnExpressionTestCases))]
public void GenericColumnExpression_GeneratesCorrectSql(ExpressionTestCase testCase)
=> ExecuteExpressionTest(testCase);
}
@@ -0,0 +1,40 @@
using Strata.SqlTools.SqlBreakdown.Classes;
using Strata.SqlTools.SqlBreakdown.Expressions;
using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Aggregate;
namespace Strata.SqlTools.SqlBreakdown.Tests.ExpressionTests;
[TestFixture]
public class SelectClauseColumnTests : ExpressionTestsBase
{
private static IEnumerable<TestCaseData> SelectClauseColumnTestCases()
{
yield return new TestCaseData("TableColumn", "foo_dept_name", "PES.DEPARTMENT_NAME AS foo_dept_name")
.SetName("TableColumn_{m}");
yield return new TestCaseData("SumFunction", "sum_net_rev", "SUM(PES.NET_REVENUE) AS sum_net_rev")
.SetName("WithSumFunction_{m}");
yield return new TestCaseData("Parameter", "my_var_col", ":FOOBAR AS my_var_col")
.SetName("WithParameter_{m}");
}
[TestCaseSource(nameof(SelectClauseColumnTestCases))]
public void SelectClauseColumn_GeneratesCorrectSql(string columnType, string alias, string expectedSql)
{
// Arrange
SelectClauseColumn column = columnType switch
{
"TableColumn" => SelectClauseColumn.TableColumn(_nameColumnExp, alias),
"SumFunction" => new SelectClauseColumn(new SumFunction(_revenueColumnExp), alias),
"Parameter" => new SelectClauseColumn(new ParameterExpression("FOOBAR"), alias),
_ => throw new ArgumentException($"Unknown column type: {columnType}")
};
// Act
var result = column.Accept(_sqlVisitor);
// Assert
Assert.That(result, Is.EqualTo(expectedSql));
}
}