using Strata.SqlTools.Breakdowns.Snowflake; using Strata.SqlTools.Markdown.Snowflake; namespace Strata.SqlTools.Markdown.Tests.Snowflake; [TestFixture] public class QueryBreakdownGeneratorTests { [Test] public void GenerateMermaidDiagram_SimpleSnowflakeQuery_GeneratesValidMermaid() { // Arrange - Using Snowflake syntax with uppercase identifiers var query = new QueryBreakdown("USER_ID, USER_NAME", "USERS"); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Simple User Query"); // Assert Assert.That(result, Does.Contain("```mermaid")); Assert.That(result, Does.Contain("flowchart TD")); Assert.That(result, Does.Contain("### Simple User Query")); Assert.That(result, Does.Contain("SELECT")); Assert.That(result, Does.Contain("FROM")); Assert.That(result, Does.Contain("```")); } [Test] public void GenerateMermaidDiagram_WithSnowflakeColonParameters_HandlesParameters() { // Arrange - Snowflake uses :parameter syntax var query = QueryBreakdown.Parse(@" SELECT USER_ID, USER_NAME, STATUS FROM USERS WHERE USER_ID = :userId AND STATUS = :status ", isMicrosoftSql: false); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("WHERE")); Assert.That(result, Does.Contain("```mermaid")); Assert.That(result, Does.Contain("flowchart TD")); } [Test] public void GenerateMermaidDiagram_WithSnowflakeCTE_ShowsWithClause() { // Arrange - Snowflake CTE with uppercase naming var query = QueryBreakdown.Parse(@" WITH ACTIVE_USERS AS ( SELECT USER_ID, USER_NAME FROM USERS WHERE STATUS = 'ACTIVE' ) SELECT U.USER_ID, U.USER_NAME, COUNT(O.ORDER_ID) AS ORDER_COUNT FROM ACTIVE_USERS U JOIN ORDERS O ON U.USER_ID = O.USER_ID GROUP BY U.USER_ID, U.USER_NAME ", isMicrosoftSql: false); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Users with Orders"); // Assert Assert.That(result, Does.Contain("WITH Clause")); Assert.That(result, Does.Contain("ACTIVE_USERS")); Assert.That(result, Does.Contain("GROUP BY")); } [Test] public void GenerateMermaidDiagram_WithSnowflakeQualify_HandlesQualifyClause() { // Arrange - Snowflake QUALIFY clause (window function filtering) var query = QueryBreakdown.Parse(@" SELECT CUSTOMER_ID, ORDER_DATE, ORDER_AMOUNT, ROW_NUMBER() OVER (PARTITION BY CUSTOMER_ID ORDER BY ORDER_DATE DESC) AS RN FROM ORDERS QUALIFY RN = 1 ", isMicrosoftSql: false); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Latest Orders per Customer"); // Assert Assert.That(result, Does.Contain("SELECT")); Assert.That(result, Does.Contain("FROM")); Assert.That(result, Does.Contain("```mermaid")); } [Test] public void GenerateMermaidDiagram_WithDoubleQuotedIdentifiers_HandlesSnowflakeQuoting() { // Arrange - Snowflake uses "identifier" for case-sensitive names var query = QueryBreakdown.Parse(@" SELECT ""userId"", ""userName"", ""emailAddress"" FROM ""Users"" WHERE ""status"" = 'ACTIVE' ", isMicrosoftSql: false); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("SELECT")); Assert.That(result, Does.Contain("WHERE")); Assert.That(result, Does.Contain("FROM")); } [Test] public void GenerateMermaidDiagram_ComplexSnowflakeQuery_GeneratesCompleteDiagram() { // Arrange - Complex Snowflake query with multiple clauses var query = QueryBreakdown.Parse(@" WITH SALES_DATA AS ( SELECT REGION, PRODUCT_ID, SUM(SALES_AMOUNT) AS TOTAL_SALES, COUNT(*) AS ORDER_COUNT FROM SALES WHERE SALE_DATE >= :startDate AND SALE_DATE <= :endDate GROUP BY REGION, PRODUCT_ID ) SELECT SD.REGION, P.PRODUCT_NAME, SD.TOTAL_SALES, SD.ORDER_COUNT FROM SALES_DATA SD JOIN PRODUCTS P ON SD.PRODUCT_ID = P.PRODUCT_ID WHERE SD.TOTAL_SALES > :minSales ORDER BY SD.TOTAL_SALES DESC ", isMicrosoftSql: false); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Regional Sales Analysis"); // Assert Assert.That(result, Does.Contain("### Regional Sales Analysis")); Assert.That(result, Does.Contain("WITH Clause")); Assert.That(result, Does.Contain("SALES_DATA")); Assert.That(result, Does.Contain("SELECT")); Assert.That(result, Does.Contain("FROM")); Assert.That(result, Does.Contain("WHERE")); Assert.That(result, Does.Contain("ORDER BY")); Assert.That(result, Does.Contain("flowchart TD")); } [Test] public void GenerateMermaidDiagram_WithGroupByAndHaving_IncludesBothClauses() { // Arrange var query = QueryBreakdown.Parse(@" SELECT CATEGORY, COUNT(*) AS PRODUCT_COUNT, AVG(PRICE) AS AVG_PRICE FROM PRODUCTS GROUP BY CATEGORY HAVING COUNT(*) > 10 AND AVG(PRICE) < 100 ", isMicrosoftSql: false); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query); // Assert Assert.That(result, Does.Contain("GROUP BY")); Assert.That(result, Does.Contain("HAVING")); } [Test] public void GenerateMermaidDiagram_NullTitle_GeneratesWithoutTitle() { // Arrange var query = new QueryBreakdown("ID", "ORDERS"); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, null); // Assert Assert.That(result, Does.Not.Contain("###")); Assert.That(result, Does.Contain("```mermaid")); Assert.That(result, Does.Contain("flowchart TD")); } [Test] public void GenerateMermaidDiagram_EmptyTitle_GeneratesWithoutTitle() { // Arrange var query = new QueryBreakdown("ORDER_ID", "ORDERS"); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, ""); // Assert Assert.That(result, Does.Not.Contain("###")); Assert.That(result, Does.Contain("SELECT")); } [Test] public void GenerateMermaidDiagram_SnowflakeTypeCasting_PreservesSyntax() { // Arrange - Snowflake :: casting syntax var query = QueryBreakdown.Parse(@" SELECT ORDER_ID::VARCHAR AS ORDER_CODE, AMOUNT::DECIMAL(10,2) AS FORMATTED_AMOUNT, CREATE_DATE::TIMESTAMP AS CREATED_AT FROM ORDERS ", isMicrosoftSql: false); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "Type Cast Example"); // Assert Assert.That(result, Does.Contain("SELECT")); Assert.That(result, Does.Contain("FROM")); Assert.That(result, Does.Contain("### Type Cast Example")); } [Test] public void GenerateMermaidDiagram_SnowflakeJsonPath_HandlesJsonNotation() { // Arrange - Snowflake JSON path notation (: for path access) var query = QueryBreakdown.Parse(@" SELECT JSON_DATA:name::STRING AS NAME, JSON_DATA:address.city::STRING AS CITY, JSON_DATA:age::NUMBER AS AGE FROM USER_JSON ", isMicrosoftSql: false); // Act var result = QueryBreakdownGenerator.GenerateMermaidDiagram(query, "JSON Data"); // Assert Assert.That(result, Does.Contain("SELECT")); Assert.That(result, Does.Contain("FROM")); Assert.That(result, Does.Contain("```mermaid")); } }