using Strata.SqlTools.Breakdowns.LinqToSql; using Strata.SqlTools.Breakdowns.SqlServer; namespace Strata.SqlTools.LinqToSql.Tests; [TestFixture] public class LinqQueryBreakdownTests { private TestDataContext _context = null!; private static readonly string[] separator = new[] { "AND" }; [SetUp] public void Setup() { _context = new TestDataContext(); } [Test] public void Analyze_SimpleSelectQuery_ExtractsCorrectClauses() { // Arrange var query = from user in TestDataContext.Users select user; // Act var breakdown = LinqQueryBreakdown.Analyze(query); // Assert Assert.That(breakdown, Is.Not.Null); Assert.Multiple(() => { Assert.That(breakdown.EntityType, Is.EqualTo(typeof(User))); Assert.That(breakdown.FromClause?.Clause, Does.Contain("User")); }); } [Test] public void Analyze_WhereClause_ExtractsCondition() { // Arrange var query = from user in TestDataContext.Users where user.Age > 21 select user; // Act var breakdown = LinqQueryBreakdown.Analyze(query); // Assert Assert.That(breakdown.WhereClause?.Clause, Is.Not.Null); Assert.That(breakdown.WhereClause?.Clause, Does.Contain("Age")); Assert.That(breakdown.WhereClause?.Clause, Does.Contain(">")); } [Test] public void Analyze_SelectWithProjection_ExtractsSelectedFields() { // Arrange var query = from user in TestDataContext.Users select new { user.Id, user.Name }; // Act var breakdown = LinqQueryBreakdown.Analyze(query); // Assert Assert.That(breakdown.SelectClause?.Clause, Is.Not.Null); Assert.That(breakdown.SelectClause?.Clause, Does.Contain("Id")); Assert.That(breakdown.SelectClause?.Clause, Does.Contain("Name")); } [Test] public void Analyze_OrderByClause_ExtractsOrdering() { // Arrange var query = from user in TestDataContext.Users orderby user.Name select user; // Act var breakdown = LinqQueryBreakdown.Analyze(query); // Assert Assert.That(breakdown.OrderByClause?.Clause, Is.Not.Null); Assert.That(breakdown.OrderByClause?.Clause, Does.Contain("Name")); } [Test] public void Analyze_MethodSyntax_ExtractsCorrectClauses() { // Arrange var query = TestDataContext.Users .Where(u => u.Age > 18) .OrderBy(u => u.Name) .Select(u => new { u.Id, u.Name }); // Act var breakdown = LinqQueryBreakdown.Analyze(query); Assert.Multiple(() => { // Assert Assert.That(breakdown.WhereClause?.Clause, Is.Not.Null); Assert.That(breakdown.OrderByClause?.Clause, Is.Not.Null); Assert.That(breakdown.SelectClause?.Clause, Is.Not.Null); }); } [Test] public void Analyze_MethodSyntax_TracksMethodChain() { // Arrange var query = TestDataContext.Users .Where(u => u.Age > 18) .OrderBy(u => u.Name) .Select(u => u.Name); // Act var breakdown = LinqQueryBreakdown.Analyze(query); // Assert Assert.That(breakdown.MethodCallChain, Is.Not.Empty); Assert.That(breakdown.MethodCallChain, Contains.Item("Where")); Assert.That(breakdown.MethodCallChain, Contains.Item("OrderBy")); Assert.That(breakdown.MethodCallChain, Contains.Item("Select")); } [Test] public void GetQuerySummary_ReturnsFormattedString() { // Arrange var query = TestDataContext.Users.Where(u => u.Age > 21); var breakdown = LinqQueryBreakdown.Analyze(query); // Act var summary = breakdown.GetQuerySummary(); // Assert Assert.That(summary, Is.Not.Empty); Assert.That(summary, Does.Contain("SELECT")); Assert.That(summary, Does.Contain("FROM")); Assert.That(summary, Does.Contain("WHERE")); } [Test] public void GetMethodChain_ReturnsMethodSequence() { // Arrange var query = TestDataContext.Users.Where(u => u.Age > 18).OrderBy(u => u.Name); var breakdown = LinqQueryBreakdown.Analyze(query); // Act var methodChain = breakdown.GetMethodChain(); // Assert Assert.That(methodChain, Does.Contain("Where")); Assert.That(methodChain, Does.Contain("OrderBy")); Assert.That(methodChain, Does.Contain("->")); } [Test] public void TryAnalyze_ValidQuery_ReturnsTrue() { // Arrange var query = TestDataContext.Users.Where(u => u.Age > 21); // Act var success = LinqQueryBreakdown.TryAnalyze(query, out var breakdown, out var error); Assert.Multiple(() => { // Assert Assert.That(success, Is.True); Assert.That(breakdown, Is.Not.Null); Assert.That(error, Is.Empty); }); } [Test] public void TryAnalyze_NullQuery_ReturnsFalse() { // Arrange IQueryable? query = null; // Act var success = LinqQueryBreakdown.TryAnalyze(query!, out var breakdown, out var error); Assert.Multiple(() => { // Assert Assert.That(success, Is.False); Assert.That(error, Is.Not.Empty); }); } [Test] public void Analyze_ComplexQuery_HandlesCombinedClauses() { // Arrange var query = from user in TestDataContext.Users where user.Age > 21 && user.IsActive orderby user.Name descending select new { user.Id, user.Name, user.Email }; // Act var breakdown = LinqQueryBreakdown.Analyze(query); // Assert Assert.That(breakdown.SelectClause?.Clause, Does.Contain("Id")); Assert.That(breakdown.SelectClause?.Clause, Does.Contain("Name")); Assert.Multiple(() => { Assert.That(breakdown.SelectClause?.Clause, Does.Contain("Email")); Assert.That(breakdown.WhereClause?.Clause, Does.Contain("Age")); }); Assert.Multiple(() => { Assert.That(breakdown.WhereClause?.Clause, Does.Contain("IsActive")); Assert.That(breakdown.OrderByClause?.Clause, Does.Contain("Name")); }); } #region Round-Trip and Query Modification Tests [Test] public void AnalyzeAndModify_AddWhereClause_GeneratesUpdatedSql() { // Arrange - Analyze an existing LINQ query var originalQuery = TestDataContext.Users.Where(u => u.Age > 21); var breakdown = LinqQueryBreakdown.Analyze(originalQuery); // Act - Add additional filter using breakdown breakdown.AddWhereClause("IsActive = 1", "AND"); var modifiedSql = breakdown.GetSql(); // Assert Assert.That(modifiedSql, Does.Contain("Age")); Assert.That(modifiedSql, Does.Contain("IsActive")); Assert.That(modifiedSql, Does.Contain("AND")); } [Test] public void AnalyzeAndModify_ChangeSelectClause_GeneratesNewProjection() { // Arrange - Analyze query with projection var originalQuery = TestDataContext.Users.Select(u => new { u.Id, u.Name }); var breakdown = LinqQueryBreakdown.Analyze(originalQuery); // Act - Modify the SELECT clause breakdown.SelectClause = new Strata.SqlTools.SqlBreakdown.Classes.SqlExpressionClause { Clause = "Id, Name, Email, Age" }; var modifiedSql = breakdown.GetSql(); // Assert Assert.That(modifiedSql, Does.Contain("Email")); Assert.That(modifiedSql, Does.Contain("Age")); Assert.That(modifiedSql, Does.Contain("Id")); Assert.That(modifiedSql, Does.Contain("Name")); } [Test] public void AnalyzeAndModify_CloneAndExtend_CreatesIndependentQuery() { // Arrange - Analyze base query var baseQuery = TestDataContext.Users.Where(u => u.Age > 18); var baseBreakdown = LinqQueryBreakdown.Analyze(baseQuery); // Act - Clone and extend var extendedBreakdown = (LinqQueryBreakdown)baseBreakdown.Clone(); extendedBreakdown.AddWhereClause("IsActive = 1", "AND"); extendedBreakdown.OrderByClause = new Strata.SqlTools.SqlBreakdown.Classes.SqlExpressionClause(splitOnComma: true) { Clause = "Name ASC" }; // Assert - Original unchanged Assert.That(baseBreakdown.OrderByClause?.Clause, Is.Null.Or.Empty); // Extended has new conditions var extendedSql = extendedBreakdown.GetSql(); Assert.That(extendedSql, Does.Contain("IsActive")); Assert.That(extendedSql, Does.Contain("ORDER BY")); } [Test] public void AnalyzeAndCompose_MultipleQueries_CreatesUnionScenario() { // Arrange - Analyze two different queries var activeUsersQuery = TestDataContext.Users.Where(u => u.IsActive); var activeBreakdown = LinqQueryBreakdown.Analyze(activeUsersQuery); var recentUsersQuery = TestDataContext.Users.Where(u => u.Age < 25); var recentBreakdown = LinqQueryBreakdown.Analyze(recentUsersQuery); // Act - Get SQL for both (could be used in UNION scenario) var activeSql = activeBreakdown.GetSql(); var recentSql = recentBreakdown.GetSql(); Assert.Multiple(() => { // Assert - Both queries are valid and different Assert.That(activeSql, Does.Contain("IsActive")); Assert.That(recentSql, Does.Contain("Age")); }); Assert.That(activeSql, Is.Not.EqualTo(recentSql)); } [Test] public void AnalyzeAndBuildFilter_IncrementallyAddConditions_BuildsComplexFilter() { // Arrange - Start with simple query var query = TestDataContext.Users; var breakdown = LinqQueryBreakdown.Analyze(query); // Act - Incrementally add filter conditions (simulating filter builder UI) breakdown.AddWhereClause("Age >= 18", "AND"); breakdown.AddWhereClause("Age <= 65", "AND"); breakdown.AddWhereClause("IsActive = 1", "AND"); var filterSql = breakdown.GetSql(); // Assert Assert.That(filterSql, Does.Contain("Age >= 18")); Assert.That(filterSql, Does.Contain("Age <= 65")); Assert.That(filterSql, Does.Contain("IsActive = 1")); // Should have multiple AND conditions var andCount = filterSql.Split(separator, StringSplitOptions.None).Length - 1; Assert.That(andCount, Is.GreaterThanOrEqualTo(2)); } [Test] public void AnalyzeAndPaginate_AddOrderAndLimits_CreatesPaginatedQuery() { // Arrange - Analyze base query var query = TestDataContext.Users.Where(u => u.IsActive); var breakdown = LinqQueryBreakdown.Analyze(query); // Act - Add pagination (ORDER BY required for consistent pagination) breakdown.OrderByClause = new Strata.SqlTools.SqlBreakdown.Classes.SqlExpressionClause(splitOnComma: true) { Clause = "Id ASC" }; // Add pagination metadata as setup clause (simulating OFFSET/FETCH or similar) breakdown.SetupClauses.Add("-- Page 1, PageSize 10"); var paginatedSql = breakdown.GetSql(); // Assert Assert.That(paginatedSql, Does.Contain("ORDER BY")); Assert.Multiple(() => { Assert.That(paginatedSql, Does.Contain("Id ASC")); Assert.That(breakdown.SetupClauses, Has.Count.EqualTo(1)); }); } [Test] public void AnalyzeAndGenerateReport_ExtractQueryMetrics_ProvidesAnalytics() { // Arrange - Complex query to analyze var query = TestDataContext.Users .Where(u => u.Age > 21) .Where(u => u.IsActive) .OrderBy(u => u.Name) .Select(u => new { u.Id, u.Name, u.Email }); var breakdown = LinqQueryBreakdown.Analyze(query); // Act - Extract metrics var methodCount = breakdown.MethodCallChain.Count; var hasProjection = breakdown.SelectClause?.Clause != "*"; var hasFilters = !string.IsNullOrEmpty(breakdown.WhereClause?.Clause); var hasOrdering = !string.IsNullOrEmpty(breakdown.OrderByClause?.Clause); var summary = breakdown.GetQuerySummary(); Assert.Multiple(() => { // Assert - Verify analytics Assert.That(methodCount, Is.GreaterThan(0)); Assert.That(hasProjection, Is.True); Assert.That(hasFilters, Is.True); Assert.That(hasOrdering, Is.True); Assert.That(summary, Does.Contain("SELECT")); }); Assert.That(summary, Does.Contain("WHERE")); Assert.That(summary, Does.Contain("ORDER BY")); } [Test] public void AnalyzeAndOptimize_RemoveSelectStar_ImprovedProjection() { // Arrange - Analyze query with SELECT * var query = TestDataContext.Users.Where(u => u.IsActive); var breakdown = LinqQueryBreakdown.Analyze(query); // Verify it initially has SELECT * var originalSql = breakdown.GetSql(); Assert.That(originalSql, Does.Contain("*").Or.Not.Contain("Id, Name")); // Act - Optimize by specifying only needed columns breakdown.SelectClause = new Strata.SqlTools.SqlBreakdown.Classes.SqlExpressionClause { Clause = "Id, Name, Email" }; var optimizedSql = breakdown.GetSql(); // Assert Assert.That(optimizedSql, Does.Contain("Id")); Assert.That(optimizedSql, Does.Contain("Name")); Assert.That(optimizedSql, Does.Contain("Email")); Assert.That(optimizedSql, Does.Not.Contain("SELECT *")); } [Test] public void AnalyzeMultipleQueries_CompareAndMerge_CreatesCompositeQuery() { // Arrange - Analyze two related queries var usersQuery = TestDataContext.Users.Where(u => u.Age > 21); var usersBreakdown = LinqQueryBreakdown.Analyze(usersQuery); var activeQuery = TestDataContext.Users.Where(u => u.IsActive); var activeBreakdown = LinqQueryBreakdown.Analyze(activeQuery); // Act - Merge conditions from both queries var mergedBreakdown = (LinqQueryBreakdown)usersBreakdown.Clone(); // Extract WHERE clause from activeBreakdown and add to merged if (!string.IsNullOrEmpty(activeBreakdown.WhereClause?.Clause)) { mergedBreakdown.AddWhereClause(activeBreakdown.WhereClause.Clause, "AND"); } var mergedSql = mergedBreakdown.GetSql(); // Assert - Merged query has both conditions Assert.That(mergedSql, Does.Contain("Age")); Assert.That(mergedSql, Does.Contain("IsActive")); } [Test] public void AnalyzeAndDocument_GenerateQueryDocumentation_CreatesReadableOutput() { // Arrange - Analyze a business query var query = TestDataContext.Orders .Where(o => o.Amount > 1000) .Where(o => o.OrderDate > DateTime.Now.AddDays(-30)) .OrderBy(o => o.OrderDate); var breakdown = LinqQueryBreakdown.Analyze(query); // Act - Generate documentation var documentation = new System.Text.StringBuilder(); documentation.AppendLine("Query: High-Value Recent Orders"); documentation.AppendLine($"Entity: {breakdown.EntityType}"); documentation.AppendLine($"Method Chain: {breakdown.GetMethodChain()}"); documentation.AppendLine($"Summary: {breakdown.GetQuerySummary()}"); documentation.AppendLine(); documentation.AppendLine("Generated SQL:"); documentation.AppendLine(breakdown.GetSql()); var doc = documentation.ToString(); // Assert - Documentation contains all key information Assert.That(doc, Does.Contain("Query:")); Assert.That(doc, Does.Contain("Entity:")); Assert.That(doc, Does.Contain("Method Chain:")); Assert.That(doc, Does.Contain("Summary:")); Assert.That(doc, Does.Contain("Generated SQL:")); Assert.That(doc, Does.Contain("Amount")); Assert.That(doc, Does.Contain("OrderDate")); } #endregion } // Test data context and entities public class TestDataContext { public static IQueryable Users => new List().AsQueryable(); public static IQueryable Orders => new List().AsQueryable(); } public class User { public int Id { get; set; } public string Name { get; set; } = string.Empty; public string Email { get; set; } = string.Empty; public int Age { get; set; } public bool IsActive { get; set; } } public class Order { public int Id { get; set; } public int UserId { get; set; } public decimal Amount { get; set; } public DateTime OrderDate { get; set; } } #region GetQuery Tests public class GetQueryTests { private TestDataContext _context = null!; [SetUp] public void Setup() { _context = new TestDataContext(); } [Test] public void GetQuery_LinqBreakdown_ReturnsEmptyByDefault() { // Arrange var query = TestDataContext.Users.Where(u => u.Age > 18); var breakdown = LinqQueryBreakdown.Analyze(query); // Act - GetQuery returns empty because LinqQueryBreakdown needs the original provider var result = breakdown.GetQuery(); // Assert Assert.That(result, Is.Empty); } [Test] public void GetQuery_SqlServerQueryBreakdown_ReturnsEmpty() { // Arrange var breakdown = new QueryBreakdown("Id, Name", "Users", "Age > 18"); // Act var result = breakdown.GetQuery(); // Assert Assert.That(result, Is.Empty); } [Test] public void GetQuery_MultipleBreakdownTypes_AllReturnEmpty() { // Arrange var linqBreakdown = LinqQueryBreakdown.Analyze(TestDataContext.Users); var sqlBreakdown = new QueryBreakdown("*", "Users"); // Act var linqResult = linqBreakdown.GetQuery(); var sqlResult = sqlBreakdown.GetQuery(); Assert.Multiple(() => { // Assert Assert.That(linqResult, Is.Empty); Assert.That(sqlResult, Is.Empty); }); } #endregion #region INSERT Analysis Tests [Test] public void AnalyzeInsert_SingleEntity_CreatesInsertBreakdown() { // Arrange var entity = new User { Id = 1, Name = "John Doe", Email = "john@example.com", Age = 30 }; // Act var breakdown = LinqQueryBreakdown.AnalyzeInsert(entity); // Assert Assert.That(breakdown, Is.Not.Null); Assert.Multiple(() => { Assert.That(breakdown.TableName.Clause, Is.EqualTo("User")); Assert.That(breakdown.InsertIntoClause.Clause, Is.Not.Empty); Assert.That(breakdown.ValuesClause.Clause, Is.Not.Empty); }); Assert.That(breakdown.InsertIntoClause.Clause, Does.Contain("Id")); Assert.That(breakdown.InsertIntoClause.Clause, Does.Contain("Name")); } [Test] public void AnalyzeInsertRange_MultipleEntities_CreatesInsertBreakdown() { // Arrange var entities = new List { new User { Id = 1, Name = "John Doe", Email = "john@example.com", Age = 30 }, new User { Id = 2, Name = "Jane Smith", Email = "jane@example.com", Age = 28 } }; // Act var breakdown = LinqQueryBreakdown.AnalyzeInsertRange(entities); // Assert Assert.That(breakdown, Is.Not.Null); Assert.Multiple(() => { Assert.That(breakdown.TableName.Clause, Is.EqualTo("User")); Assert.That(breakdown.InsertIntoClause.Clause, Is.Not.Empty); Assert.That(breakdown.ValuesClause.Clause, Does.Contain("(")); }); } [Test] public void AnalyzeInsert_NullEntity_ThrowsArgumentNullException() { // Act & Assert Assert.Throws(() => LinqQueryBreakdown.AnalyzeInsert(null!)); } #endregion #region DELETE Analysis Tests [Test] public void AnalyzeDelete_WithFilterExpression_CreatesDeleteBreakdown() { // Arrange var filterExpression = System.Linq.Expressions.Expression.Lambda>( System.Linq.Expressions.Expression.Constant(true), System.Linq.Expressions.Expression.Parameter(typeof(User), "u") ); // Act var breakdown = LinqQueryBreakdown.AnalyzeDelete(filterExpression); // Assert Assert.That(breakdown, Is.Not.Null); Assert.That(breakdown.FromClause.Clause, Is.EqualTo("User")); } [Test] public void AnalyzeDelete_NullFilter_ThrowsArgumentNullException() { // Act & Assert Assert.Throws(() => LinqQueryBreakdown.AnalyzeDelete(null!)); } #endregion #region UPDATE Analysis Tests [Test] public void AnalyzeUpdate_WithFilterAndUpdateExpressions_CreatesUpdateBreakdown() { // Arrange var filterExpr = System.Linq.Expressions.Expression.Lambda>( System.Linq.Expressions.Expression.Constant(true), System.Linq.Expressions.Expression.Parameter(typeof(User), "u") ); var updateExpr = System.Linq.Expressions.Expression.Lambda>( System.Linq.Expressions.Expression.Constant(new User()), System.Linq.Expressions.Expression.Parameter(typeof(User), "u") ); // Act var breakdown = LinqQueryBreakdown.AnalyzeUpdate(filterExpr, updateExpr); // Assert Assert.That(breakdown, Is.Not.Null); Assert.That(breakdown.TableName.Clause, Is.EqualTo("User")); } [Test] public void AnalyzeUpdate_NullFilter_ThrowsArgumentNullException() { // Arrange var updateExpr = System.Linq.Expressions.Expression.Lambda>( System.Linq.Expressions.Expression.Constant(new User()), System.Linq.Expressions.Expression.Parameter(typeof(User), "u") ); // Act & Assert Assert.Throws(() => LinqQueryBreakdown.AnalyzeUpdate(null!, updateExpr)); } [Test] public void AnalyzeUpdate_NullUpdateExpression_ThrowsArgumentNullException() { // Arrange var filterExpr = System.Linq.Expressions.Expression.Lambda>( System.Linq.Expressions.Expression.Constant(true), System.Linq.Expressions.Expression.Parameter(typeof(User), "u") ); // Act & Assert Assert.Throws(() => LinqQueryBreakdown.AnalyzeUpdate(filterExpr, null!)); } #endregion #region PROCEDURE Analysis Tests [Test] public void AnalyzeProcedure_WithName_CreatesProcedureBreakdown() { // Arrange const string procName = "sp_GetUsers"; // Act var breakdown = LinqQueryBreakdown.AnalyzeProcedure(procName); // Assert Assert.That(breakdown, Is.Not.Null); Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo(procName)); } [Test] public void AnalyzeProcedure_WithParameters_CreatesProcedureBreakdownWithParams() { // Arrange const string procName = "sp_GetUsersByAge"; var parameters = new object[] { 18, 65 }; // Act var breakdown = LinqQueryBreakdown.AnalyzeProcedure(procName, parameters); // Assert Assert.That(breakdown, Is.Not.Null); Assert.Multiple(() => { Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo(procName)); Assert.That(breakdown.Parameters, Is.Not.Empty); }); Assert.That(breakdown.Parameters, Has.Count.EqualTo(2)); } [Test] public void AnalyzeProcedure_NullOrEmptyName_ThrowsArgumentException() { // Act & Assert Assert.Throws(() => LinqQueryBreakdown.AnalyzeProcedure(null!)); Assert.Throws(() => LinqQueryBreakdown.AnalyzeProcedure("")); } #endregion #region TRACE Analysis Tests [Test] public void AnalyzeTrace_WithValidQuery_ReturnsTraceString() { // Arrange var query = TestDataContext.Users.Where(u => u.Age > 18); // Act var trace = LinqQueryBreakdown.AnalyzeTrace(query); // Assert Assert.That(trace, Is.Not.Null.And.Not.Empty); Assert.That(trace, Does.Contain("User")); Assert.That(trace, Does.Contain("Query Provider")); Assert.That(trace, Does.Contain("Timestamp")); } [Test] public void AnalyzeTrace_WithExecutionContext_IncludesContextInTrace() { // Arrange var query = TestDataContext.Users; const string context = "Initial Load"; // Act var trace = LinqQueryBreakdown.AnalyzeTrace(query, context); // Assert Assert.That(trace, Is.Not.Null); Assert.That(trace, Does.Contain(context)); Assert.That(trace, Does.Contain("Execution Context")); } [Test] public void AnalyzeTrace_NullQuery_ThrowsArgumentNullException() { // Act & Assert Assert.Throws(() => LinqQueryBreakdown.AnalyzeTrace(null!)); } #endregion #region Conversion Tests [Test] public void ConvertToSqlServerBreakdown_CopiesAllClauses() { // Arrange var query = TestDataContext.Users.Where(u => u.Age > 21).OrderBy(u => u.Name); var breakdown = LinqQueryBreakdown.Analyze(query); // Act var sqlServerBreakdown = breakdown.ConvertToSqlServerBreakdown(); // Assert Assert.That(sqlServerBreakdown, Is.Not.Null); Assert.Multiple(() => { Assert.That(sqlServerBreakdown.SelectClause?.Clause, Is.EqualTo(breakdown.SelectClause?.Clause)); Assert.That(sqlServerBreakdown.FromClause?.Clause, Is.EqualTo(breakdown.FromClause?.Clause)); Assert.That(sqlServerBreakdown.WhereClause?.Clause, Is.EqualTo(breakdown.WhereClause?.Clause)); Assert.That(sqlServerBreakdown.OrderByClause?.Clause, Is.EqualTo(breakdown.OrderByClause?.Clause)); }); } [Test] public void ConvertToPostgreSqlBreakdown_CopiesAllClauses() { // Arrange var query = TestDataContext.Users .Where(u => u.IsActive) .OrderBy(u => u.Name) .Select(u => new { u.Id, u.Name }); var breakdown = LinqQueryBreakdown.Analyze(query); // Act var postgresBreakdown = breakdown.ConvertToPostgreSqlBreakdown(); // Assert Assert.That(postgresBreakdown, Is.Not.Null); Assert.Multiple(() => { Assert.That(postgresBreakdown.SelectClause?.Clause, Is.EqualTo(breakdown.SelectClause?.Clause)); Assert.That(postgresBreakdown.FromClause?.Clause, Is.EqualTo(breakdown.FromClause?.Clause)); Assert.That(postgresBreakdown.WhereClause?.Clause, Is.EqualTo(breakdown.WhereClause?.Clause)); Assert.That(postgresBreakdown.OrderByClause?.Clause, Is.EqualTo(breakdown.OrderByClause?.Clause)); }); } [Test] public void ConvertToSnowflakeBreakdown_CopiesAllClauses() { // Arrange var query = TestDataContext.Users.Where(u => u.Age > 21).OrderBy(u => u.Name); var breakdown = LinqQueryBreakdown.Analyze(query); // Act var snowflakeBreakdown = breakdown.ConvertToSnowflakeBreakdown(); // Assert Assert.That(snowflakeBreakdown, Is.Not.Null); Assert.Multiple(() => { Assert.That(snowflakeBreakdown.SelectClause?.Clause, Is.EqualTo(breakdown.SelectClause?.Clause)); Assert.That(snowflakeBreakdown.FromClause?.Clause, Is.EqualTo(breakdown.FromClause?.Clause)); Assert.That(snowflakeBreakdown.WhereClause?.Clause, Is.EqualTo(breakdown.WhereClause?.Clause)); Assert.That(snowflakeBreakdown.OrderByClause?.Clause, Is.EqualTo(breakdown.OrderByClause?.Clause)); }); } [Test] public void ConvertToSqlServerBreakdown_WithComments_PreservesComments() { // Arrange var breakdown = new LinqQueryBreakdown("Id, Name", "Users", "Age > 21"); breakdown.SelectClause.Comment = "Select user columns"; breakdown.WhereClause.Comment = "Filter adult users"; // Act var sqlServerBreakdown = breakdown.ConvertToSqlServerBreakdown(); Assert.Multiple(() => { // Assert Assert.That(sqlServerBreakdown.SelectClause?.Comment, Is.EqualTo("Select user columns")); Assert.That(sqlServerBreakdown.WhereClause?.Comment, Is.EqualTo("Filter adult users")); }); } [Test] public void ConvertToPostgreSqlBreakdown_WithComplexQuery_CopieAllClauses() { // Arrange var query = TestDataContext.Users .Where(u => u.IsActive && u.Age >= 18) .OrderByDescending(u => u.Age); var breakdown = LinqQueryBreakdown.Analyze(query); // Act var postgresBreakdown = breakdown.ConvertToPostgreSqlBreakdown(); Assert.Multiple(() => { // Assert Assert.That(postgresBreakdown.SelectClause?.Clause, Is.Not.Null); Assert.That(postgresBreakdown.FromClause?.Clause, Is.Not.Null); Assert.That(postgresBreakdown.WhereClause?.Clause, Is.Not.Null); Assert.That(postgresBreakdown.GroupByClause?.Clause, Is.Not.Null); Assert.That(postgresBreakdown.OrderByClause?.Clause, Is.Not.Null); }); } [Test] public void ConvertToSnowflakeBreakdown_PreservesAllClauseInformation() { // Arrange var breakdown = LinqQueryBreakdown.Analyze(TestDataContext.Users.OrderBy(u => u.Name)); // Act var snowflakeBreakdown = breakdown.ConvertToSnowflakeBreakdown(); Assert.Multiple(() => { // Assert Assert.That(snowflakeBreakdown.FromClause?.Clause, Is.EqualTo(breakdown.FromClause?.Clause)); Assert.That(snowflakeBreakdown.OrderByClause?.Clause, Is.EqualTo(breakdown.OrderByClause?.Clause)); }); } [Test] public void ConvertToSqlServerBreakdown_InstancesAreIndependent() { // Arrange var breakdown = LinqQueryBreakdown.Analyze(TestDataContext.Users.Where(u => u.Age > 21)); var sqlServerBreakdown = breakdown.ConvertToSqlServerBreakdown(); // Act - Modify the SQL Server breakdown sqlServerBreakdown.SelectClause.Clause = "Id, Name, Email"; // Assert - Original should be unchanged Assert.That(breakdown.SelectClause?.Clause, Is.Not.EqualTo(sqlServerBreakdown.SelectClause?.Clause)); } [Test] public void ConvertChainMultipleTimes_EachConversionIndependent() { // Arrange var breakdown = LinqQueryBreakdown.Analyze(TestDataContext.Users.OrderBy(u => u.Name)); // Act var sqlServer1 = breakdown.ConvertToSqlServerBreakdown(); var sqlServer2 = breakdown.ConvertToSqlServerBreakdown(); // Assert - Both should have same data but be different instances Assert.That(sqlServer1, Is.Not.SameAs(sqlServer2)); Assert.That(sqlServer1.OrderByClause?.Clause, Is.EqualTo(sqlServer2.OrderByClause?.Clause)); } #endregion }