From b0e75231ff0b72d81899a9122b4adf2fdeecfee4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 14 Dec 2025 08:23:45 +0000 Subject: [PATCH 1/2] Initial plan From f8131c1e13a5ad6783cd72de47a50b6065fe9861 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 14 Dec 2025 09:15:00 +0000 Subject: [PATCH 2/2] Add 62 new unit tests covering SchemaObjectName, DatabaseConnection, DatabaseView, InlinerOptions, InlinerResult, error handling, and complex scenarios Co-authored-by: stevehansen <2143488+stevehansen@users.noreply.github.com> --- src/SqlInliner.Tests/ComplexScenarioTests.cs | 164 ++++++++++++++++++ .../DatabaseConnectionTests.cs | 116 +++++++++++++ src/SqlInliner.Tests/DatabaseViewTests.cs | 118 +++++++++++++ src/SqlInliner.Tests/ErrorHandlingTests.cs | 106 +++++++++++ src/SqlInliner.Tests/InlinerOptionsTests.cs | 42 +++++ src/SqlInliner.Tests/InlinerResultTests.cs | 134 ++++++++++++++ src/SqlInliner.Tests/SchemaObjectNameTests.cs | 49 ++++++ 7 files changed, 729 insertions(+) create mode 100644 src/SqlInliner.Tests/ComplexScenarioTests.cs create mode 100644 src/SqlInliner.Tests/DatabaseConnectionTests.cs create mode 100644 src/SqlInliner.Tests/DatabaseViewTests.cs create mode 100644 src/SqlInliner.Tests/ErrorHandlingTests.cs create mode 100644 src/SqlInliner.Tests/InlinerOptionsTests.cs create mode 100644 src/SqlInliner.Tests/InlinerResultTests.cs create mode 100644 src/SqlInliner.Tests/SchemaObjectNameTests.cs diff --git a/src/SqlInliner.Tests/ComplexScenarioTests.cs b/src/SqlInliner.Tests/ComplexScenarioTests.cs new file mode 100644 index 0000000..9f0cbd5 --- /dev/null +++ b/src/SqlInliner.Tests/ComplexScenarioTests.cs @@ -0,0 +1,164 @@ +using NUnit.Framework; + +namespace SqlInliner.Tests; + +public class ComplexScenarioTests +{ + private DatabaseConnection connection; + private readonly InlinerOptions options = InlinerOptions.Recommended(); + + [SetUp] + public void Setup() + { + connection = new(); + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VPeople"), + "CREATE VIEW dbo.VPeople AS SELECT p.Id, p.FirstName, p.LastName, p.IsActive FROM dbo.People p"); + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VOrders"), + "CREATE VIEW dbo.VOrders AS SELECT o.Id, o.PersonId, o.Amount, o.OrderDate FROM dbo.Orders o"); + } + + [Test] + public void ViewWithLeftOuterJoin_Inlines() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id, p.FirstName, o.Amount FROM dbo.VPeople p LEFT OUTER JOIN dbo.VOrders o ON p.Id = o.PersonId"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.Orders")); + Assert.IsFalse(inliner.Result.ConvertedSql.Contains("dbo.VPeople")); + Assert.IsFalse(inliner.Result.ConvertedSql.Contains("dbo.VOrders")); + } + + [Test] + public void ViewWithRightOuterJoin_Inlines() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id, p.FirstName, o.Amount FROM dbo.VPeople p RIGHT OUTER JOIN dbo.VOrders o ON p.Id = o.PersonId"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.Orders")); + } + + [Test] + public void ViewWithFullOuterJoin_Inlines() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id, p.FirstName, o.Amount FROM dbo.VPeople p FULL OUTER JOIN dbo.VOrders o ON p.Id = o.PersonId"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.Orders")); + } + + [Test] + public void ViewWithMultipleJoins_Inlines() + { + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VProducts"), + "CREATE VIEW dbo.VProducts AS SELECT pr.Id, pr.Name, pr.Price FROM dbo.Products pr"); + + const string viewSql = @"CREATE VIEW dbo.VTest AS + SELECT p.Id, p.FirstName, o.Amount, pr.Name + FROM dbo.VPeople p + INNER JOIN dbo.VOrders o ON p.Id = o.PersonId + INNER JOIN dbo.VProducts pr ON o.Id = pr.Id"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.Orders")); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.Products")); + } + + [Test] + public void ThreeLevelNesting_Inlines() + { + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VLevel2"), + "CREATE VIEW dbo.VLevel2 AS SELECT p.Id, p.FirstName FROM dbo.VPeople p"); + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VLevel3"), + "CREATE VIEW dbo.VLevel3 AS SELECT l2.Id, l2.FirstName FROM dbo.VLevel2 l2"); + + const string viewSql = "CREATE VIEW dbo.VLevel4 AS SELECT l3.Id FROM dbo.VLevel3 l3"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + Assert.IsFalse(inliner.Result.ConvertedSql.Contains("VLevel2")); + Assert.IsFalse(inliner.Result.ConvertedSql.Contains("VLevel3")); + } + + [Test] + public void ViewWithSubquery_Inlines() + { + const string viewSql = @"CREATE VIEW dbo.VTest AS + SELECT p.Id, p.FirstName, + (SELECT COUNT(*) FROM dbo.VOrders o WHERE o.PersonId = p.Id) OrderCount + FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + } + + [Test] + public void ViewWithGroupBy_Inlines() + { + const string viewSql = @"CREATE VIEW dbo.VTest AS + SELECT p.Id, p.FirstName, COUNT(*) OrderCount + FROM dbo.VPeople p + INNER JOIN dbo.VOrders o ON p.Id = o.PersonId + GROUP BY p.Id, p.FirstName"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + } + + [Test] + public void ViewWithOrderBy_Inlines() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT TOP 100 p.Id, p.FirstName FROM dbo.VPeople p ORDER BY p.FirstName"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + } + + [Test] + public void ViewWithCaseStatement_Inlines() + { + const string viewSql = @"CREATE VIEW dbo.VTest AS + SELECT p.Id, + CASE WHEN p.IsActive = 1 THEN 'Active' ELSE 'Inactive' END Status + FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + } + + [Test] + public void ViewWithDistinct_Inlines() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT DISTINCT p.LastName FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("DISTINCT")); + } + + [Test] + public void ViewWithMultipleWhereClauses_Inlines() + { + const string viewSql = @"CREATE VIEW dbo.VTest AS + SELECT p.Id, p.FirstName + FROM dbo.VPeople p + WHERE p.IsActive = 1 AND p.LastName IS NOT NULL"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + } +} diff --git a/src/SqlInliner.Tests/DatabaseConnectionTests.cs b/src/SqlInliner.Tests/DatabaseConnectionTests.cs new file mode 100644 index 0000000..f745dbc --- /dev/null +++ b/src/SqlInliner.Tests/DatabaseConnectionTests.cs @@ -0,0 +1,116 @@ +using NUnit.Framework; + +namespace SqlInliner.Tests; + +public class DatabaseConnectionTests +{ + [Test] + public void EmptyConnection_HasNoViews() + { + var connection = new DatabaseConnection(); + Assert.AreEqual(0, connection.Views.Count); + } + + [Test] + public void EmptyConnection_HasNullConnection() + { + var connection = new DatabaseConnection(); + Assert.IsNull(connection.Connection); + } + + [Test] + public void AddViewDefinition_AddsToViews() + { + var connection = new DatabaseConnection(); + var viewName = DatabaseConnection.ToObjectName("dbo", "VTest"); + const string definition = "CREATE VIEW dbo.VTest AS SELECT 1"; + + connection.AddViewDefinition(viewName, definition); + + Assert.AreEqual(1, connection.Views.Count); + } + + [Test] + public void AddViewDefinition_CanRetrieveDefinition() + { + var connection = new DatabaseConnection(); + var viewName = DatabaseConnection.ToObjectName("dbo", "VTest"); + const string definition = "CREATE VIEW dbo.VTest AS SELECT 1"; + + connection.AddViewDefinition(viewName, definition); + var retrieved = connection.GetViewDefinition(viewName.GetName()); + + Assert.AreEqual(definition, retrieved); + } + + [Test] + public void AddViewDefinition_MultipleViews_AllAccessible() + { + var connection = new DatabaseConnection(); + var view1 = DatabaseConnection.ToObjectName("dbo", "VTest1"); + var view2 = DatabaseConnection.ToObjectName("dbo", "VTest2"); + const string def1 = "CREATE VIEW dbo.VTest1 AS SELECT 1"; + const string def2 = "CREATE VIEW dbo.VTest2 AS SELECT 2"; + + connection.AddViewDefinition(view1, def1); + connection.AddViewDefinition(view2, def2); + + Assert.AreEqual(2, connection.Views.Count); + Assert.AreEqual(def1, connection.GetViewDefinition(view1.GetName())); + Assert.AreEqual(def2, connection.GetViewDefinition(view2.GetName())); + } + + [Test] + public void IsView_ViewExists_ReturnsTrue() + { + var connection = new DatabaseConnection(); + var viewName = DatabaseConnection.ToObjectName("dbo", "VTest"); + connection.AddViewDefinition(viewName, "CREATE VIEW dbo.VTest AS SELECT 1"); + + Assert.IsTrue(connection.IsView(viewName)); + } + + [Test] + public void IsView_ViewDoesNotExist_ReturnsFalse() + { + var connection = new DatabaseConnection(); + var viewName = DatabaseConnection.ToObjectName("dbo", "VTest"); + + Assert.IsFalse(connection.IsView(viewName)); + } + + [Test] + public void IsView_DifferentSchema_ReturnsFalse() + { + var connection = new DatabaseConnection(); + var viewName1 = DatabaseConnection.ToObjectName("dbo", "VTest"); + var viewName2 = DatabaseConnection.ToObjectName("other", "VTest"); + connection.AddViewDefinition(viewName1, "CREATE VIEW dbo.VTest AS SELECT 1"); + + Assert.IsFalse(connection.IsView(viewName2)); + } + + [Test] + public void AddViewDefinition_UpdatesExistingView() + { + var connection = new DatabaseConnection(); + var viewName = DatabaseConnection.ToObjectName("dbo", "VTest"); + const string def1 = "CREATE VIEW dbo.VTest AS SELECT 1"; + const string def2 = "CREATE VIEW dbo.VTest AS SELECT 2"; + + connection.AddViewDefinition(viewName, def1); + connection.AddViewDefinition(viewName, def2); + + Assert.AreEqual(def2, connection.GetViewDefinition(viewName.GetName())); + } + + [Test] + public void ToObjectName_CreatesValidSchemaObjectName() + { + var objectName = DatabaseConnection.ToObjectName("myschema", "myview"); + + Assert.IsNotNull(objectName); + Assert.AreEqual("myschema", objectName.SchemaIdentifier.Value); + Assert.AreEqual("myview", objectName.BaseIdentifier.Value); + } +} diff --git a/src/SqlInliner.Tests/DatabaseViewTests.cs b/src/SqlInliner.Tests/DatabaseViewTests.cs new file mode 100644 index 0000000..fa3fc34 --- /dev/null +++ b/src/SqlInliner.Tests/DatabaseViewTests.cs @@ -0,0 +1,118 @@ +using NUnit.Framework; + +namespace SqlInliner.Tests; + +public class DatabaseViewTests +{ + private DatabaseConnection connection; + + [SetUp] + public void Setup() + { + connection = new(); + } + + [Test] + public void CreateOrAlter_ReplacesCREATEVIEW() + { + const string viewSql = "CREATE VIEW dbo.V AS SELECT 1"; + var result = DatabaseView.CreateOrAlter(viewSql); + Assert.IsTrue(result.StartsWith("CREATE OR ALTER VIEW")); + } + + [Test] + public void CreateOrAlter_WithLowerCase_Replaces() + { + const string viewSql = "create view dbo.V as select 1"; + var result = DatabaseView.CreateOrAlter(viewSql); + StringAssert.StartsWith("CREATE OR ALTER VIEW", result); + } + + [Test] + public void CreateOrAlter_WithMixedCase_Replaces() + { + const string viewSql = "Create View dbo.V As SELECT 1"; + var result = DatabaseView.CreateOrAlter(viewSql); + StringAssert.StartsWith("CREATE OR ALTER VIEW", result); + } + + [Test] + public void CreateOrAlter_WithExtraSpaces_Replaces() + { + const string viewSql = "CREATE VIEW dbo.V AS SELECT 1"; + var result = DatabaseView.CreateOrAlter(viewSql); + StringAssert.StartsWith("CREATE OR ALTER VIEW", result); + } + + [Test] + public void CreateOrAlter_WithNewline_Replaces() + { + const string viewSql = "CREATE\nVIEW dbo.V AS SELECT 1"; + var result = DatabaseView.CreateOrAlter(viewSql); + StringAssert.StartsWith("CREATE OR ALTER VIEW", result); + } + + [Test] + public void CreateOrAlter_AlreadyCreateOrAlter_Unchanged() + { + const string viewSql = "CREATE OR ALTER VIEW dbo.V AS SELECT 1"; + var result = DatabaseView.CreateOrAlter(viewSql); + Assert.AreEqual(viewSql, result); + } + + [Test] + public void FromSql_ValidView_ReturnsViewWithNoErrors() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT 1 AS Col"; + var (view, errors) = DatabaseView.FromSql(connection, viewSql); + Assert.IsNotNull(view); + Assert.AreEqual(0, errors.Count); + Assert.AreEqual("[dbo].[VTest]", view.ViewName); + } + + [Test] + public void FromSql_CreateOrAlterView_ReturnsViewWithNoErrors() + { + const string viewSql = "CREATE OR ALTER VIEW dbo.VTest AS SELECT 1 AS Col"; + var (view, errors) = DatabaseView.FromSql(connection, viewSql); + Assert.IsNotNull(view); + Assert.AreEqual(0, errors.Count); + Assert.AreEqual("[dbo].[VTest]", view.ViewName); + } + + [Test] + public void FromSql_InvalidSyntax_ReturnsNullWithErrors() + { + const string viewSql = "CREATE OR VIEW dbo.VTest AS SELECT 1"; + var (view, errors) = DatabaseView.FromSql(connection, viewSql); + Assert.IsNull(view); + Assert.Greater(errors.Count, 0); + } + + [Test] + public void FromSql_ViewWithMultipleColumns_ParsesCorrectly() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT 1 AS Col1, 2 AS Col2, 3 AS Col3"; + var (view, errors) = DatabaseView.FromSql(connection, viewSql); + Assert.IsNotNull(view); + Assert.AreEqual(0, errors.Count); + } + + [Test] + public void FromSql_ViewWithWhere_ParsesCorrectly() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT Id FROM dbo.Table WHERE IsActive = 1"; + var (view, errors) = DatabaseView.FromSql(connection, viewSql); + Assert.IsNotNull(view); + Assert.AreEqual(0, errors.Count); + } + + [Test] + public void FromSql_ViewWithJoin_ParsesCorrectly() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT t1.Id FROM dbo.Table1 t1 INNER JOIN dbo.Table2 t2 ON t1.Id = t2.Id"; + var (view, errors) = DatabaseView.FromSql(connection, viewSql); + Assert.IsNotNull(view); + Assert.AreEqual(0, errors.Count); + } +} diff --git a/src/SqlInliner.Tests/ErrorHandlingTests.cs b/src/SqlInliner.Tests/ErrorHandlingTests.cs new file mode 100644 index 0000000..c06a8f5 --- /dev/null +++ b/src/SqlInliner.Tests/ErrorHandlingTests.cs @@ -0,0 +1,106 @@ +using NUnit.Framework; + +namespace SqlInliner.Tests; + +public class ErrorHandlingTests +{ + private DatabaseConnection connection; + private readonly InlinerOptions options = InlinerOptions.Recommended(); + + [SetUp] + public void Setup() + { + connection = new(); + } + + [Test] + public void InvalidSql_ReturnsErrorsInSql() + { + const string viewSql = "CREATE OR VIEW dbo.X AS SELECT 0"; + + var inliner = new DatabaseViewInliner(connection, viewSql); + Assert.IsNull(inliner.View); + Assert.IsTrue(inliner.Sql.Contains("Failed parsing query")); + } + + [Test] + public void ViewWithoutAlias_AddsError() + { + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VPeople"), "CREATE VIEW dbo.VPeople AS SELECT Id FROM dbo.People"); + + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT Id FROM dbo.VPeople"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.Greater(inliner.Errors.Count, 0); + Assert.IsTrue(inliner.Errors[0].Contains("without using an alias")); + } + + [Test] + public void MultipleViewsWithoutAlias_ListsAllInError() + { + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VPeople"), "CREATE VIEW dbo.VPeople AS SELECT Id FROM dbo.People"); + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VOrders"), "CREATE VIEW dbo.VOrders AS SELECT Id FROM dbo.Orders"); + + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT VPeople.Id, VOrders.Id FROM dbo.VPeople INNER JOIN dbo.VOrders ON VPeople.Id = VOrders.PersonId"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.Greater(inliner.Errors.Count, 0); + } + + [Test] + public void SinglePartIdentifier_AddsWarning() + { + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VPeople"), "CREATE VIEW dbo.VPeople AS SELECT Id, Name FROM dbo.People"); + + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT Id FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.Greater(inliner.Warnings.Count, 0); + Assert.IsTrue(inliner.Warnings[0].Contains("single part identifiers")); + } + + [Test] + public void NoColumnsSelected_AddsWarning() + { + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VPeople"), "CREATE VIEW dbo.VPeople AS SELECT Id, Name FROM dbo.People"); + + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT 1 AS Val FROM dbo.Table t INNER JOIN dbo.VPeople p ON 1=1"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.Greater(inliner.Warnings.Count, 0); + } + + [Test] + public void OnlyOneColumnSelected_AddsWarningWhenJoinsNotStripped() + { + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VPeople"), "CREATE VIEW dbo.VPeople AS SELECT p.Id, p.Name FROM dbo.People p"); + + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeople p WHERE p.Id = 1"; + + var inliner = new DatabaseViewInliner(connection, viewSql); + Assert.Greater(inliner.Warnings.Count, 0); + Assert.IsTrue(inliner.Warnings[0].Contains("Only 1 column")); + } + + [Test] + public void ValidSql_NoErrors() + { + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VPeople"), "CREATE VIEW dbo.VPeople AS SELECT p.Id, p.Name FROM dbo.People p"); + + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id, p.Name FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + } + + [Test] + public void ValidSqlWithAlias_NoErrors() + { + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VPeople"), "CREATE VIEW dbo.VPeople AS SELECT p.Id, p.Name FROM dbo.People p"); + + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT v.Id PersonId, v.Name PersonName FROM dbo.VPeople v"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.AreEqual(0, inliner.Errors.Count); + } +} diff --git a/src/SqlInliner.Tests/InlinerOptionsTests.cs b/src/SqlInliner.Tests/InlinerOptionsTests.cs new file mode 100644 index 0000000..8ac1a95 --- /dev/null +++ b/src/SqlInliner.Tests/InlinerOptionsTests.cs @@ -0,0 +1,42 @@ +using NUnit.Framework; + +namespace SqlInliner.Tests; + +public class InlinerOptionsTests +{ + [Test] + public void DefaultOptions_StripUnusedColumnsIsTrue() + { + var options = new InlinerOptions(); + Assert.IsTrue(options.StripUnusedColumns); + } + + [Test] + public void DefaultOptions_StripUnusedJoinsIsFalse() + { + var options = new InlinerOptions(); + Assert.IsFalse(options.StripUnusedJoins); + } + + [Test] + public void RecommendedOptions_BothOptionsEnabled() + { + var options = InlinerOptions.Recommended(); + Assert.IsTrue(options.StripUnusedColumns); + Assert.IsTrue(options.StripUnusedJoins); + } + + [Test] + public void SetStripUnusedColumns_CanBeDisabled() + { + var options = new InlinerOptions { StripUnusedColumns = false }; + Assert.IsFalse(options.StripUnusedColumns); + } + + [Test] + public void SetStripUnusedJoins_CanBeEnabled() + { + var options = new InlinerOptions { StripUnusedJoins = true }; + Assert.IsTrue(options.StripUnusedJoins); + } +} diff --git a/src/SqlInliner.Tests/InlinerResultTests.cs b/src/SqlInliner.Tests/InlinerResultTests.cs new file mode 100644 index 0000000..556e748 --- /dev/null +++ b/src/SqlInliner.Tests/InlinerResultTests.cs @@ -0,0 +1,134 @@ +using NUnit.Framework; + +namespace SqlInliner.Tests; + +public class InlinerResultTests +{ + private DatabaseConnection connection; + private readonly InlinerOptions options = InlinerOptions.Recommended(); + + [SetUp] + public void Setup() + { + connection = new(); + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VPeople"), + "CREATE VIEW dbo.VPeople AS SELECT p.Id, p.FirstName, p.LastName FROM dbo.People p"); + } + + [Test] + public void Result_ContainsOriginalSql() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNotNull(inliner.Result); + Assert.IsTrue(inliner.Result.Sql.Contains(DatabaseView.BeginOriginal)); + Assert.IsTrue(inliner.Result.Sql.Contains(DatabaseView.EndOriginal)); + Assert.IsTrue(inliner.Result.Sql.Contains(viewSql)); + } + + [Test] + public void Result_ContainsConvertedSql() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNotNull(inliner.Result); + Assert.IsNotNull(inliner.Result.ConvertedSql); + Assert.IsTrue(inliner.Result.ConvertedSql.Contains("dbo.People")); + } + + [Test] + public void Result_ContainsReferencedViews() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNotNull(inliner.Result); + Assert.Greater(inliner.Result.KnownViews.Count, 0); + Assert.IsTrue(inliner.Result.Sql.Contains("Referenced views")); + } + + [Test] + public void Result_ContainsGeneratedTimestamp() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNotNull(inliner.Result); + Assert.IsTrue(inliner.Result.Sql.Contains("Generated on")); + } + + [Test] + public void Result_ContainsElapsedTime() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNotNull(inliner.Result); + Assert.Greater(inliner.Result.Elapsed.TotalMilliseconds, 0); + } + + [Test] + public void Result_ContainsStrippedCounts() + { + connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VPeopleExtra"), + "CREATE VIEW dbo.VPeopleExtra AS SELECT p.Id, p.FirstName, p.LastName, p.Extra1, p.Extra2 FROM dbo.People p"); + + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeopleExtra p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNotNull(inliner.Result); + Assert.IsTrue(inliner.Result.Sql.Contains("Removed:")); + Assert.IsTrue(inliner.Result.Sql.Contains("select columns")); + } + + [Test] + public void Result_ContainsWarningsSection() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNotNull(inliner.Result); + Assert.IsTrue(inliner.Result.Sql.Contains("Warnings")); + } + + [Test] + public void Result_ContainsErrorsSection() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNotNull(inliner.Result); + Assert.IsTrue(inliner.Result.Sql.Contains("Errors")); + } + + [Test] + public void Result_WithNoViews_IsNull() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT 1 AS Col"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNull(inliner.Result); + } + + [Test] + public void Result_KnownViewsIncludesMainView() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNotNull(inliner.Result); + Assert.IsTrue(inliner.Result.KnownViews.ContainsKey("[dbo].[VTest]")); + } + + [Test] + public void Result_KnownViewsIncludesReferencedViews() + { + const string viewSql = "CREATE VIEW dbo.VTest AS SELECT p.Id FROM dbo.VPeople p"; + + var inliner = new DatabaseViewInliner(connection, viewSql, options); + Assert.IsNotNull(inliner.Result); + Assert.IsTrue(inliner.Result.KnownViews.ContainsKey("[dbo].[VPeople]")); + } +} diff --git a/src/SqlInliner.Tests/SchemaObjectNameTests.cs b/src/SqlInliner.Tests/SchemaObjectNameTests.cs new file mode 100644 index 0000000..420a2aa --- /dev/null +++ b/src/SqlInliner.Tests/SchemaObjectNameTests.cs @@ -0,0 +1,49 @@ +using Microsoft.SqlServer.TransactSql.ScriptDom; +using NUnit.Framework; + +namespace SqlInliner.Tests; + +public class SchemaObjectNameTests +{ + [Test] + public void GetName_WithSchemaAndTable_ReturnsQuotedName() + { + var objectName = DatabaseConnection.ToObjectName("dbo", "MyTable"); + var result = objectName.GetName(); + Assert.AreEqual("[dbo].[MyTable]", result); + } + + [Test] + public void GetName_WithCustomSchema_ReturnsQuotedName() + { + var objectName = DatabaseConnection.ToObjectName("custom", "MyView"); + var result = objectName.GetName(); + Assert.AreEqual("[custom].[MyView]", result); + } + + [Test] + public void GetName_WithSpecialCharactersInName_ReturnsQuotedName() + { + var objectName = DatabaseConnection.ToObjectName("dbo", "My View With Spaces"); + var result = objectName.GetName(); + Assert.AreEqual("[dbo].[My View With Spaces]", result); + } + + [Test] + public void GetName_WithoutSchema_UsesDefaultDbo() + { + var objectName = new SchemaObjectName(); + objectName.Identifiers.Add(new Identifier { Value = "MyTable" }); + var result = objectName.GetName(); + Assert.AreEqual("[dbo].[MyTable]", result); + } + + [Test] + public void ToObjectName_CreatesObjectWithTwoIdentifiers() + { + var objectName = DatabaseConnection.ToObjectName("schema", "table"); + Assert.AreEqual(2, objectName.Identifiers.Count); + Assert.AreEqual("schema", objectName.Identifiers[0].Value); + Assert.AreEqual("table", objectName.Identifiers[1].Value); + } +}