Driven by `dotnet format analyzers --diagnostics NUnit2045`. The fixer
groups consecutive independent `Assert.That(...)` calls into
`Assert.Multiple(() => { ... })`, so a failing assertion no longer
short-circuits the block — every failure inside the group is reported,
which gives much better diagnostics on multi-property tests.
Audit confirmed no Assert.Throws / Assert.Fail / Assert.Catch / Assert.Pass
/ Assert.DoesNotThrow got pulled inside a Multiple block (those need to
short-circuit). All 1180 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
577 lines
18 KiB
C#
577 lines
18 KiB
C#
using Strata.SqlTools.Breakdowns.SqlServer;
|
|
using Strata.SqlTools.SqlBreakdown.Classes;
|
|
using Strata.SqlTools.SqlBreakdown.Expressions;
|
|
|
|
namespace Strata.SqlTools.SqlBreakdown.Tests.SqlServer;
|
|
|
|
[TestFixture]
|
|
public class WithClauseTests
|
|
{
|
|
#region Constructor Tests
|
|
|
|
[Test]
|
|
public void Constructor_Default_CreatesEmptyInstance()
|
|
{
|
|
// Arrange & Act
|
|
var withClause = new WithClause();
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert
|
|
Assert.That(withClause.TableName, Is.EqualTo(string.Empty));
|
|
Assert.That(withClause.Sql, Is.Null);
|
|
Assert.That(withClause.Query, Is.Null);
|
|
Assert.That(withClause.Clause, Is.Null.Or.Empty);
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void Constructor_WithTableNameAndQuery_SetsProperties()
|
|
{
|
|
// Arrange
|
|
var tableName = "active_users";
|
|
var query = new QueryBreakdown("id, name", "users", "active = 1");
|
|
|
|
// Act
|
|
var withClause = new WithClause(tableName, query);
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert
|
|
Assert.That(withClause.TableName, Is.EqualTo(tableName));
|
|
Assert.That(withClause.Query, Is.EqualTo(query));
|
|
Assert.That(withClause.Sql, Is.Not.Null);
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void Constructor_WithTableNameAndQuery_ThrowsOnNullTableName()
|
|
{
|
|
// Arrange
|
|
var query = new QueryBreakdown("id, name", "users");
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentNullException>(() => new WithClause(null!, query));
|
|
}
|
|
|
|
[Test]
|
|
public void Constructor_WithTableNameAndQuery_ThrowsOnNullQuery()
|
|
{
|
|
// Arrange
|
|
var tableName = "active_users";
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentNullException>(() => new WithClause(tableName, (QueryBreakdown)null!));
|
|
}
|
|
|
|
[Test]
|
|
public void Constructor_WithTableNameAndSql_SetsProperties()
|
|
{
|
|
// Arrange
|
|
var tableName = "active_users";
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "id, name" },
|
|
FromClause = new SqlClause { Clause = "users" }
|
|
};
|
|
|
|
// Act
|
|
var withClause = new WithClause(tableName, sqlClauses);
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert
|
|
Assert.That(withClause.TableName, Is.EqualTo(tableName));
|
|
Assert.That(withClause.Sql, Is.EqualTo(sqlClauses));
|
|
Assert.That(withClause.Query, Is.Null);
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void Constructor_WithTableNameAndSql_ThrowsOnNullTableName()
|
|
{
|
|
// Arrange
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "id" }
|
|
};
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentNullException>(() => new WithClause(null!, sqlClauses));
|
|
}
|
|
|
|
[Test]
|
|
public void Constructor_WithTableNameAndSql_ThrowsOnNullSql()
|
|
{
|
|
// Arrange
|
|
var tableName = "active_users";
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentNullException>(() => new WithClause(tableName, (SqlClauses)null!));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Property Synchronization Tests
|
|
|
|
[Test]
|
|
public void Sql_WhenQueryExists_ReturnsComputedClauses()
|
|
{
|
|
// Arrange
|
|
var query = new QueryBreakdown("user_id, name", "users");
|
|
var withClause = new WithClause("active_users", query);
|
|
|
|
// Act
|
|
var sql = withClause.Sql;
|
|
|
|
// Assert
|
|
Assert.That(sql, Is.Not.Null);
|
|
Assert.Multiple(() =>
|
|
{
|
|
Assert.That(sql!.SelectClause?.Clause, Is.EqualTo("user_id, name"));
|
|
Assert.That(sql.FromClause?.Clause, Is.EqualTo("users"));
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void Sql_WhenQueryNull_ReturnsStoredClauses()
|
|
{
|
|
// Arrange
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "column1" },
|
|
FromClause = new SqlClause { Clause = "table1" }
|
|
};
|
|
var withClause = new WithClause("test_cte", sqlClauses);
|
|
|
|
// Act
|
|
var sql = withClause.Sql;
|
|
|
|
// Assert
|
|
Assert.That(sql, Is.EqualTo(sqlClauses));
|
|
}
|
|
|
|
[Test]
|
|
public void Sql_SetWhenQueryNull_StoresClauses()
|
|
{
|
|
// Arrange
|
|
var withClause = new WithClause { TableName = "test_cte" };
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "column1" },
|
|
FromClause = new SqlClause { Clause = "table1" }
|
|
};
|
|
|
|
// Act
|
|
withClause.Sql = sqlClauses;
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert
|
|
Assert.That(withClause.Sql, Is.EqualTo(sqlClauses));
|
|
Assert.That(withClause.Query, Is.Null);
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void Sql_SetWhenQueryExists_AppliesToQuery()
|
|
{
|
|
// Arrange
|
|
var query = new QueryBreakdown();
|
|
var withClause = new WithClause { TableName = "test_cte", Query = query };
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "column1" },
|
|
FromClause = new SqlClause { Clause = "table1" }
|
|
};
|
|
|
|
// Act
|
|
withClause.Sql = sqlClauses;
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert - Clauses are applied to the Query
|
|
Assert.That(query.SelectClause.Clause, Is.EqualTo("column1"));
|
|
Assert.That(query.FromClause.Clause, Is.EqualTo("table1"));
|
|
// And Sql property returns the applied clauses (from Query, not stored)
|
|
Assert.That(withClause.Sql?.SelectClause?.Clause, Is.EqualTo("column1"));
|
|
Assert.That(withClause.Sql?.FromClause?.Clause, Is.EqualTo("table1"));
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void Query_SetWhenSqlAlreadySet_AppliesSqlToQuery()
|
|
{
|
|
// Arrange
|
|
var withClause = new WithClause { TableName = "test_cte" };
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "column1" },
|
|
FromClause = new SqlClause { Clause = "table1" }
|
|
};
|
|
withClause.Sql = sqlClauses;
|
|
|
|
// Act
|
|
var query = new QueryBreakdown();
|
|
withClause.Query = query;
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert - Stored SQL is applied to Query
|
|
Assert.That(query.SelectClause.Clause, Is.EqualTo("column1"));
|
|
Assert.That(query.FromClause.Clause, Is.EqualTo("table1"));
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void Query_SetWhenSqlAlreadySet_ClearsSqlStorage()
|
|
{
|
|
// Arrange
|
|
var withClause = new WithClause { TableName = "test_cte" };
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "column1" }
|
|
};
|
|
withClause.Sql = sqlClauses;
|
|
|
|
// Act
|
|
var query = new QueryBreakdown();
|
|
withClause.Query = query;
|
|
|
|
// Assert - Stored _sql should be cleared, but Sql property still returns from Query
|
|
Assert.That(withClause.Sql, Is.Not.Null);
|
|
}
|
|
|
|
[Test]
|
|
public void Sql_SetThenQuerySet_BidirectionalSync()
|
|
{
|
|
// Arrange: Set Sql first, then Query
|
|
var withClause = new WithClause { TableName = "test_cte" };
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "old_column" },
|
|
FromClause = new SqlClause { Clause = "old_table" }
|
|
};
|
|
withClause.Sql = sqlClauses;
|
|
|
|
// Act: Setting new Query should apply stored Sql
|
|
var query = new QueryBreakdown();
|
|
withClause.Query = query;
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert
|
|
Assert.That(query.SelectClause.Clause, Is.EqualTo("old_column"));
|
|
Assert.That(query.FromClause.Clause, Is.EqualTo("old_table"));
|
|
Assert.That(withClause.Query, Is.EqualTo(query));
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void Query_SetThenSqlSet_BidirectionalSync()
|
|
{
|
|
// Arrange: Set Query first
|
|
var query = new QueryBreakdown();
|
|
var withClause = new WithClause { TableName = "test_cte", Query = query };
|
|
|
|
// Act: Setting new Sql should apply to Query
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "new_column" },
|
|
FromClause = new SqlClause { Clause = "new_table" }
|
|
};
|
|
withClause.Sql = sqlClauses;
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert
|
|
Assert.That(query.SelectClause.Clause, Is.EqualTo("new_column"));
|
|
Assert.That(query.FromClause.Clause, Is.EqualTo("new_table"));
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetClauses Integration Tests
|
|
|
|
[Test]
|
|
public void GetClauses_FromQueryBreakdown_ReturnsAllClauseProperties()
|
|
{
|
|
// Arrange
|
|
var query = new QueryBreakdown("id, name", "users", "active = 1");
|
|
query.GroupByClause = new SqlExpressionClause { Clause = "department" };
|
|
query.HavingClause = new SqlExpressionClause { Clause = "COUNT(*) > 5" };
|
|
query.OrderByClause = new SqlExpressionClause { Clause = "name ASC" };
|
|
|
|
var withClause = new WithClause("user_summary", query);
|
|
|
|
// Act
|
|
var sql = withClause.Sql;
|
|
|
|
// Assert
|
|
Assert.That(sql, Is.Not.Null);
|
|
Assert.Multiple(() =>
|
|
{
|
|
Assert.That(sql!.SelectClause?.Clause, Is.EqualTo("id, name"));
|
|
Assert.That(sql.FromClause?.Clause, Is.EqualTo("users"));
|
|
Assert.That(sql.WhereClause?.Clause, Is.EqualTo("active = 1"));
|
|
Assert.That(sql.GroupByClause?.Clause, Is.EqualTo("department"));
|
|
Assert.That(sql.HavingClause?.Clause, Is.EqualTo("COUNT(*) > 5"));
|
|
Assert.That(sql.OrderByClause?.Clause, Is.EqualTo("name ASC"));
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ApplyClauses Integration Tests
|
|
|
|
[Test]
|
|
public void ApplyClauses_WhenSqlSet_AppliesAllClauses()
|
|
{
|
|
// Arrange
|
|
var query = new QueryBreakdown();
|
|
var withClause = new WithClause { TableName = "test_cte", Query = query };
|
|
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "id, name" },
|
|
FromClause = new SqlClause { Clause = "users" },
|
|
WhereClause = new SqlExpressionClause { Clause = "active = 1" },
|
|
GroupByClause = new SqlExpressionClause { Clause = "department" },
|
|
HavingClause = new SqlExpressionClause { Clause = "COUNT(*) > 5" },
|
|
OrderByClause = new SqlExpressionClause { Clause = "name ASC" }
|
|
};
|
|
|
|
// Act
|
|
withClause.Sql = sqlClauses;
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert
|
|
Assert.That(query.SelectClause.Clause, Is.EqualTo("id, name"));
|
|
Assert.That(query.FromClause.Clause, Is.EqualTo("users"));
|
|
Assert.That(query.WhereClause.Clause, Is.EqualTo("active = 1"));
|
|
Assert.That(query.GroupByClause.Clause, Is.EqualTo("department"));
|
|
Assert.That(query.HavingClause.Clause, Is.EqualTo("COUNT(*) > 5"));
|
|
Assert.That(query.OrderByClause.Clause, Is.EqualTo("name ASC"));
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void ApplyClauses_WhenSqlPartial_AppliesOnlyNonNullClauses()
|
|
{
|
|
// Arrange
|
|
var query = new QueryBreakdown("original_select", "original_from");
|
|
var withClause = new WithClause { TableName = "test_cte", Query = query };
|
|
|
|
var sqlClauses = new SqlClauses
|
|
{
|
|
SelectClause = new SqlExpressionClause { Clause = "new_select" }
|
|
// Only SelectClause is set; others are null
|
|
};
|
|
|
|
// Act
|
|
withClause.Sql = sqlClauses;
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert
|
|
Assert.That(query.SelectClause.Clause, Is.EqualTo("new_select"));
|
|
Assert.That(query.FromClause.Clause, Is.EqualTo("original_from")); // Unchanged
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Comment Handling Tests
|
|
|
|
[Test]
|
|
public void WithClause_PreservesCommentProperty()
|
|
{
|
|
// Arrange
|
|
var comment = "-- This CTE selects active users";
|
|
var withClause = new WithClause { TableName = "active_users", Comment = comment };
|
|
|
|
// Act & Assert
|
|
Assert.That(withClause.Comment, Is.EqualTo(comment));
|
|
}
|
|
|
|
[Test]
|
|
public void WithClause_PreservesClauseProperty()
|
|
{
|
|
// Arrange
|
|
var clause = "SELECT id, name FROM users WHERE active = 1";
|
|
var withClause = new WithClause { TableName = "active_users", Clause = clause };
|
|
|
|
// Act & Assert
|
|
Assert.That(withClause.Clause, Is.EqualTo(clause));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Edge Cases and Null Handling
|
|
|
|
[Test]
|
|
public void Sql_SetToNull_ClearsStorage()
|
|
{
|
|
// Arrange
|
|
var sqlClauses = new SqlClauses { SelectClause = new SqlExpressionClause { Clause = "id" } };
|
|
var withClause = new WithClause { TableName = "test_cte", Sql = sqlClauses };
|
|
|
|
// Act
|
|
withClause.Sql = null;
|
|
|
|
// Assert
|
|
Assert.That(withClause.Sql, Is.Null);
|
|
}
|
|
|
|
[Test]
|
|
public void Query_SetToNull_ClearsReference()
|
|
{
|
|
// Arrange
|
|
var query = new QueryBreakdown("id", "users");
|
|
var withClause = new WithClause("test_cte", query);
|
|
|
|
// Act
|
|
withClause.Query = null;
|
|
|
|
// Assert
|
|
Assert.That(withClause.Query, Is.Null);
|
|
}
|
|
|
|
[Test]
|
|
public void ApplyClauses_WithNullSqlClauses_DoesNotThrow()
|
|
{
|
|
// Arrange
|
|
var query = new QueryBreakdown("id", "users");
|
|
var withClause = new WithClause { TableName = "test_cte", Query = query };
|
|
|
|
// Act & Assert
|
|
Assert.DoesNotThrow(() => withClause.Sql = null);
|
|
}
|
|
|
|
[Test]
|
|
public void Sql_WhenBothQueryAndStorageNull_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var withClause = new WithClause { TableName = "test_cte" };
|
|
|
|
// Act
|
|
var result = withClause.Sql;
|
|
|
|
// Assert
|
|
Assert.That(result, Is.Null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ComplexScenario Tests
|
|
|
|
[Test]
|
|
public void ComplexScenario_NestedCTE_WithParameters()
|
|
{
|
|
// Arrange: Create inner CTE with parameters
|
|
var innerQuery = new QueryBreakdown("id, name", "users", "created_date >= @StartDate");
|
|
innerQuery.AddParameter("@StartDate", DateTime.Today);
|
|
|
|
var innerCte = new WithClause("recent_users", innerQuery);
|
|
|
|
// Arrange: Create outer CTE that uses inner CTE
|
|
var outerQuery = new QueryBreakdown("*", "recent_users");
|
|
var outerCte = new WithClause("user_report", outerQuery);
|
|
|
|
// Act
|
|
var innerSql = innerCte.Sql;
|
|
var outerSql = outerCte.Sql;
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Assert - Inner CTE has parameter and correct clauses
|
|
Assert.That(innerQuery.ParameterList.Count(), Is.EqualTo(1));
|
|
Assert.That(innerSql?.SelectClause?.Clause, Is.EqualTo("id, name"));
|
|
Assert.That(innerSql?.WhereClause?.Clause, Is.EqualTo("created_date >= @StartDate"));
|
|
|
|
// Assert - Outer CTE references inner CTE
|
|
Assert.That(outerSql?.SelectClause?.Clause, Is.EqualTo("*"));
|
|
Assert.That(outerSql?.FromClause?.Clause, Is.EqualTo("recent_users"));
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void ComplexScenario_MultipleClauseUpdates()
|
|
{
|
|
// Arrange
|
|
var query = new QueryBreakdown("id", "users");
|
|
var withClause = new WithClause("test_cte", query);
|
|
|
|
// Act: Update clauses via Sql property multiple times
|
|
var sql1 = new SqlClauses { SelectClause = new SqlExpressionClause { Clause = "updated_column_1" } };
|
|
withClause.Sql = sql1;
|
|
|
|
var sql2 = new SqlClauses { SelectClause = new SqlExpressionClause { Clause = "updated_column_2" } };
|
|
withClause.Sql = sql2;
|
|
|
|
// Assert
|
|
Assert.That(query.SelectClause.Clause, Is.EqualTo("updated_column_2"));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSql Integration Tests
|
|
|
|
[Test]
|
|
public void GetSql_WithSingleCTE_GeneratesCorrectSyntax()
|
|
{
|
|
// Arrange
|
|
var cteQuery = new QueryBreakdown("id, name", "users", "active = 1");
|
|
var mainQuery = new QueryBreakdown("*", "active_users");
|
|
mainQuery.AddWithClause("active_users", cteQuery);
|
|
|
|
// Act
|
|
var sql = mainQuery.GetSql();
|
|
|
|
// Assert
|
|
Assert.That(sql, Does.Contain("WITH"));
|
|
Assert.That(sql, Does.Contain("active_users"));
|
|
Assert.That(sql, Does.Contain("AS"));
|
|
Assert.Multiple(() =>
|
|
{
|
|
// Check for keywords/content (allowing for formatting variations)
|
|
Assert.That(sql.ToUpper(), Does.Contain("SELECT"));
|
|
Assert.That(sql, Does.Contain("id, name"));
|
|
});
|
|
Assert.That(sql, Does.Contain("users"));
|
|
Assert.That(sql, Does.Contain("active = 1"));
|
|
}
|
|
|
|
[Test]
|
|
public void GetSql_WithMultipleCTEs_GeneratesCorrectSyntax()
|
|
{
|
|
// Arrange
|
|
var cte1 = new QueryBreakdown("id, name", "users", "active = 1");
|
|
var cte2 = new QueryBreakdown("user_id, order_count", "orders");
|
|
|
|
var mainQuery = new QueryBreakdown("*", "active_users");
|
|
mainQuery.AddWithClause("active_users", cte1);
|
|
mainQuery.AddWithClause("user_orders", cte2);
|
|
|
|
// Act
|
|
var sql = mainQuery.GetSql();
|
|
|
|
// Assert
|
|
Assert.That(sql, Does.Contain("WITH"));
|
|
Assert.That(sql, Does.Contain("active_users"));
|
|
Assert.That(sql, Does.Contain("user_orders"));
|
|
// Verify order: first CTE comes before second CTE
|
|
var pos1 = sql.IndexOf("active_users");
|
|
var pos2 = sql.IndexOf("user_orders");
|
|
Assert.Multiple(() =>
|
|
{
|
|
Assert.That(pos1, Is.GreaterThan(-1));
|
|
Assert.That(pos2, Is.GreaterThan(-1));
|
|
});
|
|
Assert.That(pos1, Is.LessThan(pos2)); }
|
|
|
|
#endregion
|
|
}
|