Files
Thom Lamb 8b0368e810
SonarQube Analysis / sonarqube (push) Failing after 3m21s
test: fix SqlBreakdown tests project
2026-05-15 13:39:14 -05:00

1179 lines
35 KiB
Plaintext

using Strata.SqlTools.Interfaces;
using System.Linq;
using System.Text;
namespace Strata.SqlTools.SqlBreakdown.Tests;
/// <summary>
/// Unit tests for the SqlBreakdownCollection class.
/// </summary>
[TestFixture]
public class SqlBreakdownCollectionTests
{
[Test]
public void Constructor_WithNoArguments_CreatesEmptyCollection()
{
// Arrange & Act
var collection = new SqlBreakdownCollection();
// Assert
Assert.That(collection.Count, Is.EqualTo(0));
Assert.That(collection.IsEmpty, Is.True);
Assert.That(collection.Breakdowns, Is.Empty);
Assert.That(collection.RawStatements, Is.Empty);
}
[Test]
public void Constructor_WithBreakdownList_InitializesCollection()
{
// Arrange
var mockBreakdowns = new List<ISqlBreakdown>
{
new MockSqlBreakdown("SELECT * FROM Table1"),
new MockSqlBreakdown("SELECT * FROM Table2")
};
// Act
var collection = new SqlBreakdownCollection(mockBreakdowns);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.IsEmpty, Is.False);
}
[Test]
public void Add_WithValidBreakdown_AddsToCollection()
{
// Arrange
var collection = new SqlBreakdownCollection();
var breakdown = new MockSqlBreakdown("SELECT * FROM Table1");
// Act
collection.Add(breakdown);
// Assert
Assert.That(collection.Count, Is.EqualTo(1));
Assert.That(collection.GetAt(0), Is.EqualTo(breakdown));
}
[Test]
public void Add_WithNullBreakdown_ThrowsArgumentNullException()
{
// Arrange
var collection = new SqlBreakdownCollection();
// Act & Assert
Assert.Throws<ArgumentNullException>(() => collection.Add(null!));
}
[Test]
public void AddRange_WithMultipleBreakdowns_AddsAllItems()
{
// Arrange
var collection = new SqlBreakdownCollection();
var breakdowns = new List<ISqlBreakdown>
{
new MockSqlBreakdown("SELECT * FROM Table1"),
new MockSqlBreakdown("SELECT * FROM Table2"),
new MockSqlBreakdown("SELECT * FROM Table3")
};
// Act
collection.AddRange(breakdowns);
// Assert
Assert.That(collection.Count, Is.EqualTo(3));
}
[Test]
public void AddRange_WithNullCollection_ThrowsArgumentNullException()
{
// Arrange
var collection = new SqlBreakdownCollection();
// Act & Assert
Assert.Throws<ArgumentNullException>(() => collection.AddRange(null!));
}
[Test]
public void Remove_WithExistingBreakdown_RemovesItem()
{
// Arrange
var breakdown = new MockSqlBreakdown("SELECT * FROM Table1");
var collection = new SqlBreakdownCollection(new[] { breakdown });
// Act
var result = collection.Remove(breakdown);
// Assert
Assert.That(result, Is.True);
Assert.That(collection.Count, Is.EqualTo(0));
}
[Test]
public void Remove_WithNonExistingBreakdown_ReturnsFalse()
{
// Arrange
var collection = new SqlBreakdownCollection(new[] { new MockSqlBreakdown("SELECT * FROM Table1") });
var otherBreakdown = new MockSqlBreakdown("SELECT * FROM Table2");
// Act
var result = collection.Remove(otherBreakdown);
// Assert
Assert.That(result, Is.False);
Assert.That(collection.Count, Is.EqualTo(1));
}
[Test]
public void Clear_WithMultipleItems_RemovesAll()
{
// Arrange
var collection = new SqlBreakdownCollection(new[]
{
new MockSqlBreakdown("SELECT * FROM Table1"),
new MockSqlBreakdown("SELECT * FROM Table2")
});
// Act
collection.Clear();
// Assert
Assert.That(collection.Count, Is.EqualTo(0));
Assert.That(collection.IsEmpty, Is.True);
}
[Test]
public void ParseBatch_WithGoSeparators_ParsesStatements()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
SELECT * FROM Table1
GO
SELECT * FROM Table2
GO
SELECT * FROM Table3
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.RawStatements.Count, Is.EqualTo(3));
Assert.That(collection.RawStatements[0], Does.Contain("Table1"));
Assert.That(collection.RawStatements[1], Does.Contain("Table2"));
Assert.That(collection.RawStatements[2], Does.Contain("Table3"));
}
[Test]
public void ParseBatch_WithMixedCaseGO_ParsesCorrectly()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
SELECT * FROM Table1
go
SELECT * FROM Table2
GO
SELECT * FROM Table3
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.RawStatements.Count, Is.EqualTo(3));
}
[Test]
public void ParseBatch_WithGoAndWhitespace_ParsesCorrectly()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
SELECT * FROM Table1
GO
SELECT * FROM Table2
GO
SELECT * FROM Table3
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.RawStatements.Count, Is.EqualTo(3));
}
[Test]
public void ParseBatch_WithEmptyStatements_FiltersOutEmptyValues()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
SELECT * FROM Table1
GO
GO
SELECT * FROM Table2
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.RawStatements.Count, Is.EqualTo(2));
Assert.That(collection.RawStatements[0], Does.Contain("Table1"));
Assert.That(collection.RawStatements[1], Does.Contain("Table2"));
}
[Test]
public void ParseBatch_WithNullInput_ThrowsArgumentNullException()
{
// Arrange
var collection = new SqlBreakdownCollection();
// Act & Assert
Assert.Throws<ArgumentNullException>(() => collection.ParseBatch(null!));
}
[Test]
public void GetCombinedSql_WithMultipleBreakdowns_CombinesSqlWithSeparator()
{
// Arrange
var breakdowns = new[]
{
new MockSqlBreakdown("SELECT * FROM Table1"),
new MockSqlBreakdown("SELECT * FROM Table2")
};
var collection = new SqlBreakdownCollection(breakdowns);
// Act
var result = collection.GetCombinedSql();
// Assert
Assert.That(result, Does.Contain("Table1"));
Assert.That(result, Does.Contain("Table2"));
Assert.That(result, Does.Contain("GO"));
}
[Test]
public void GetCombinedSql_WithEmptyCollection_ReturnsEmpty()
{
// Arrange
var collection = new SqlBreakdownCollection();
// Act
var result = collection.GetCombinedSql();
// Assert
Assert.That(result, Is.Empty);
}
[Test]
public void GetCombinedSql_WithCustomSeparator_UsesCustomSeparator()
{
// Arrange
var breakdowns = new[]
{
new MockSqlBreakdown("SELECT * FROM Table1"),
new MockSqlBreakdown("SELECT * FROM Table2")
};
var collection = new SqlBreakdownCollection(breakdowns);
// Act
var result = collection.GetCombinedSql(true, ";");
// Assert
Assert.That(result, Does.Contain(";"));
Assert.That(result, Does.Not.Contain("GO"));
}
[Test]
public void GetBatchSql_WithRawStatements_CombinesWithGO()
{
// Arrange
var collection = new SqlBreakdownCollection();
collection.ParseBatch(@"
SELECT * FROM Table1
GO
SELECT * FROM Table2
");
// Act
var result = collection.GetBatchSql();
// Assert
Assert.That(result, Does.Contain("Table1"));
Assert.That(result, Does.Contain("GO"));
Assert.That(result, Does.Contain("Table2"));
}
[Test]
public void GetBatchSql_WithEmptyCollection_ReturnsEmpty()
{
// Arrange
var collection = new SqlBreakdownCollection();
// Act
var result = collection.GetBatchSql();
// Assert
Assert.That(result, Is.Empty);
}
[Test]
public void Where_WithValidPredicate_FiltersBreakdowns()
{
// Arrange
var breakdowns = new[]
{
new MockSqlBreakdown("SELECT * FROM Table1"),
new MockSqlBreakdown("SELECT * FROM Table2"),
new MockSqlBreakdown("SELECT * FROM Table3")
};
var collection = new SqlBreakdownCollection(breakdowns);
// Act
var filtered = collection.Where(b => b.ToString()!.Contains("Table2")).ToList();
// Assert
Assert.That(filtered.Count, Is.EqualTo(1));
Assert.That(filtered[0].ToString()!, Does.Contain("Table2"));
}
[Test]
public void Select_WithValidSelector_ProjectsBreakdowns()
{
// Arrange
var breakdowns = new[]
{
new MockSqlBreakdown("SELECT * FROM Table1"),
new MockSqlBreakdown("SELECT * FROM Table2")
};
var collection = new SqlBreakdownCollection(breakdowns);
// Act
var projected = collection.Select(b => b.ToString()!.Length).ToList();
// Assert
Assert.That(projected.Count, Is.EqualTo(2));
Assert.That(projected[0], Is.GreaterThan(0));
}
[Test]
public void GetAt_WithValidIndex_ReturnsBreakdown()
{
// Arrange
var breakdown1 = new MockSqlBreakdown("SELECT * FROM Table1");
var breakdown2 = new MockSqlBreakdown("SELECT * FROM Table2");
var collection = new SqlBreakdownCollection(new[] { breakdown1, breakdown2 });
// Act
var result = collection.GetAt(1);
// Assert
Assert.That(result, Is.EqualTo(breakdown2));
}
[Test]
public void GetAt_WithInvalidIndex_ThrowsIndexOutOfRangeException()
{
// Arrange
var collection = new SqlBreakdownCollection(new[] { new MockSqlBreakdown("SELECT * FROM Table1") });
// Act & Assert
Assert.Throws<IndexOutOfRangeException>(() => collection.GetAt(5));
}
[Test]
public void FirstOrDefault_WithMatchingPredicate_ReturnsBreakdown()
{
// Arrange
var breakdowns = new[]
{
new MockSqlBreakdown("SELECT * FROM Table1"),
new MockSqlBreakdown("SELECT * FROM Table2")
};
var collection = new SqlBreakdownCollection(breakdowns);
// Act
var result = collection.FirstOrDefault(b => b.ToString()!.Contains("Table2"));
// Assert
Assert.That(result, Is.Not.Null);
Assert.That(result!.ToString(), Does.Contain("Table2"));
}
[Test]
public void FirstOrDefault_WithNoMatch_ReturnsNull()
{
// Arrange
var collection = new SqlBreakdownCollection(new[] { new MockSqlBreakdown("SELECT * FROM Table1") });
// Act
var result = collection.FirstOrDefault(b => b.ToString()!.Contains("NonExistent"));
// Assert
Assert.That(result, Is.Null);
}
[Test]
public void GetRawStatementAt_WithValidIndex_ReturnsStatement()
{
// Arrange
var collection = new SqlBreakdownCollection();
collection.ParseBatch(@"
SELECT * FROM Table1
GO
SELECT * FROM Table2
");
// Act
var result = collection.GetRawStatementAt(1);
// Assert
Assert.That(result, Does.Contain("Table2"));
}
[Test]
public void GetRawStatementAt_WithInvalidIndex_ThrowsIndexOutOfRangeException()
{
// Arrange
var collection = new SqlBreakdownCollection();
collection.ParseBatch("SELECT * FROM Table1");
// Act & Assert
Assert.Throws<IndexOutOfRangeException>(() => collection.GetRawStatementAt(5));
}
[Test]
public void ToString_ReturnsFormattedSql()
{
// Arrange
var breakdowns = new[]
{
new MockSqlBreakdown("SELECT * FROM Table1"),
new MockSqlBreakdown("SELECT * FROM Table2")
};
var collection = new SqlBreakdownCollection(breakdowns);
// Act
var result = collection.ToString();
// Assert
Assert.That(result, Does.Contain("Table1"));
Assert.That(result, Does.Contain("Table2"));
Assert.That(result, Does.Contain("GO"));
}
// ============================================================
// CRUD Tests - Complete SQL Statement Coverage
// ============================================================
#region CREATE Tests
[Test]
public void ParseBatch_WithCreateTableStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
CREATE TABLE Users (
Id INT PRIMARY KEY,
Name NVARCHAR(100),
Email NVARCHAR(100)
)
GO
CREATE TABLE Orders (
OrderId INT PRIMARY KEY,
UserId INT FOREIGN KEY REFERENCES Users(Id),
OrderDate DATETIME
)
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("CREATE TABLE Users"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("CREATE TABLE Orders"));
}
[Test]
public void ParseBatch_WithCreateIndexStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
CREATE INDEX idx_Users_Email ON Users(Email)
GO
CREATE UNIQUE INDEX idx_Orders_OrderDate ON Orders(OrderDate)
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("CREATE INDEX"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("UNIQUE"));
}
[Test]
public void ParseBatch_WithCreateProcedureStatement_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
CREATE PROCEDURE sp_GetUserById
@UserId INT
AS
BEGIN
SELECT * FROM Users WHERE Id = @UserId
END
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.GreaterThanOrEqualTo(1));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("CREATE PROCEDURE"));
}
#endregion
#region INSERT (CREATE Data) Tests
[Test]
public void ParseBatch_WithInsertStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
INSERT INTO Users (Id, Name, Email) VALUES (1, 'John Doe', 'john@example.com')
GO
INSERT INTO Users (Id, Name, Email) VALUES (2, 'Jane Smith', 'jane@example.com')
GO
INSERT INTO Users (Id, Name, Email) VALUES (3, 'Bob Johnson', 'bob@example.com')
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(3));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("INSERT INTO Users"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("Jane Smith"));
Assert.That(collection.GetRawStatementAt(2), Does.Contain("Bob Johnson"));
}
[Test]
public void ParseBatch_WithInsertSelectStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
INSERT INTO UsersArchive
SELECT Id, Name, Email FROM Users WHERE CreatedDate < '2020-01-01'
GO
INSERT INTO OrdersBackup
SELECT OrderId, UserId, OrderDate FROM Orders WHERE OrderDate < DATEADD(year, -1, GETDATE())
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("INSERT INTO UsersArchive"));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("SELECT"));
}
[Test]
public void ParseBatch_WithBulkInsertStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
BULK INSERT Users FROM 'C:\data\users.csv'
WITH (FIELDTERMINATOR=',', ROWTERMINATOR='\n')
GO
BULK INSERT Orders FROM 'C:\data\orders.csv'
WITH (FIELDTERMINATOR=',', ROWTERMINATOR='\n')
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("BULK INSERT"));
}
#endregion
#region SELECT (READ) Tests
[Test]
public void ParseBatch_WithComplexSelectStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
SELECT u.Id, u.Name, COUNT(o.OrderId) AS OrderCount
FROM Users u
LEFT JOIN Orders o ON u.Id = o.UserId
WHERE u.CreatedDate > '2020-01-01'
GROUP BY u.Id, u.Name
HAVING COUNT(o.OrderId) > 0
ORDER BY OrderCount DESC
GO
SELECT * FROM Orders WHERE OrderDate BETWEEN '2020-01-01' AND '2021-12-31'
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("LEFT JOIN"));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("GROUP BY"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("BETWEEN"));
}
[Test]
public void ParseBatch_WithSelectWithCommonTableExpression_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
WITH UserOrders AS (
SELECT UserId, OrderId, OrderDate
FROM Orders
WHERE OrderDate > '2020-01-01'
)
SELECT u.Id, u.Name, uo.OrderId
FROM Users u
INNER JOIN UserOrders uo ON u.Id = uo.UserId
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.GreaterThanOrEqualTo(1));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("WITH UserOrders AS"));
}
[Test]
public void ParseBatch_WithSelectFromMultipleTables_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
SELECT u.Id, u.Name, o.OrderId, p.ProductName
FROM Users u
JOIN Orders o ON u.Id = o.UserId
JOIN OrderItems oi ON o.OrderId = oi.OrderId
JOIN Products p ON oi.ProductId = p.Id
WHERE u.Country = 'USA'
GO
SELECT * FROM UserProfiles WHERE UserId IN (SELECT Id FROM Users)
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("JOIN"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("IN"));
}
#endregion
#region UPDATE Tests
[Test]
public void ParseBatch_WithUpdateStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
UPDATE Users SET Name = 'John Updated', ModifiedDate = GETDATE() WHERE Id = 1
GO
UPDATE Orders SET Status = 'Shipped' WHERE OrderDate < DATEADD(day, -30, GETDATE())
GO
UPDATE Products SET Price = Price * 1.1 WHERE Category = 'Electronics'
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(3));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("UPDATE Users"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("Status"));
Assert.That(collection.GetRawStatementAt(2), Does.Contain("Price * 1.1"));
}
[Test]
public void ParseBatch_WithUpdateFromSelectStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
UPDATE u
SET u.LastOrderDate = (SELECT MAX(OrderDate) FROM Orders WHERE UserId = u.Id)
FROM Users u
WHERE u.Id IN (SELECT DISTINCT UserId FROM Orders)
GO
UPDATE Products
SET Quantity = Quantity - 1
FROM OrderItems oi
WHERE Products.Id = oi.ProductId AND oi.OrderId = 100
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("UPDATE u"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("Quantity - 1"));
}
[Test]
public void ParseBatch_WithUpdateWithJoinStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
UPDATE Orders
SET OrderStatus = 'Processed'
FROM Orders o
JOIN OrderItems oi ON o.OrderId = oi.OrderId
WHERE oi.Quantity > 50
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.GreaterThanOrEqualTo(1));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("UPDATE Orders"));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("JOIN"));
}
#endregion
#region DELETE Tests
[Test]
public void ParseBatch_WithDeleteStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
DELETE FROM Orders WHERE OrderDate < '2019-01-01'
GO
DELETE FROM UserProfiles WHERE UserId NOT IN (SELECT Id FROM Users)
GO
DELETE FROM AuditLog WHERE LogDate < DATEADD(year, -2, GETDATE())
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(3));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("DELETE FROM Orders"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("NOT IN"));
Assert.That(collection.GetRawStatementAt(2), Does.Contain("DATEADD"));
}
[Test]
public void ParseBatch_WithDeleteFromSelectStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
DELETE o FROM Orders o
WHERE NOT EXISTS (SELECT 1 FROM OrderItems oi WHERE oi.OrderId = o.OrderId)
GO
DELETE FROM Users
WHERE Id IN (SELECT UserId FROM Orders WHERE OrderStatus = 'Cancelled')
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("EXISTS"));
}
[Test]
public void ParseBatch_WithDeleteWithJoinStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
DELETE Orders
FROM Orders o
INNER JOIN OrderStatuses os ON o.StatusId = os.Id
WHERE os.StatusName = 'Archived'
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.GreaterThanOrEqualTo(1));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("DELETE Orders"));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("INNER JOIN"));
}
#endregion
#region DROP Tests
[Test]
public void ParseBatch_WithDropTableStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
DROP TABLE IF EXISTS OrderItems
GO
DROP TABLE IF EXISTS Orders
GO
DROP TABLE IF EXISTS Users
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(3));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("DROP TABLE"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("DROP TABLE"));
}
[Test]
public void ParseBatch_WithDropIndexAndProcedureStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
DROP INDEX IF EXISTS idx_Users_Email ON Users
GO
DROP PROCEDURE IF EXISTS sp_GetUserById
GO
DROP VIEW IF EXISTS vw_UserOrders
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(3));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("DROP INDEX"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("PROCEDURE"));
Assert.That(collection.GetRawStatementAt(2), Does.Contain("VIEW"));
}
#endregion
#region Mixed CRUD Operations Tests
[Test]
public void ParseBatch_WithMixedCrudOperations_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
CREATE TABLE Users (
Id INT PRIMARY KEY,
Name NVARCHAR(100),
Email NVARCHAR(100)
)
GO
INSERT INTO Users (Id, Name, Email) VALUES (1, 'John Doe', 'john@example.com')
GO
INSERT INTO Users (Id, Name, Email) VALUES (2, 'Jane Smith', 'jane@example.com')
GO
SELECT * FROM Users WHERE Id = 1
GO
UPDATE Users SET Name = 'John Updated' WHERE Id = 1
GO
DELETE FROM Users WHERE Id = 2
GO
DROP TABLE Users
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(7));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("CREATE TABLE"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("INSERT"));
Assert.That(collection.GetRawStatementAt(3), Does.Contain("SELECT"));
Assert.That(collection.GetRawStatementAt(4), Does.Contain("UPDATE"));
Assert.That(collection.GetRawStatementAt(5), Does.Contain("DELETE"));
Assert.That(collection.GetRawStatementAt(6), Does.Contain("DROP"));
}
[Test]
public void ParseBatch_WithComplexMultipleStatements_ParsesAllStatements()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
CREATE TABLE Products (
Id INT PRIMARY KEY,
Name NVARCHAR(100),
Price DECIMAL(10, 2),
Quantity INT
)
GO
INSERT INTO Products (Id, Name, Price, Quantity)
SELECT Id, ProductName, BasePrice, StockQuantity
FROM StagingProducts
WHERE IsActive = 1
GO
UPDATE Products SET Price = Price * 1.1 WHERE Quantity < 10
GO
SELECT p.Name,
COUNT(oi.Id) AS OrderCount,
SUM(oi.Quantity) AS TotalSold
FROM Products p
LEFT JOIN OrderItems oi ON p.Id = oi.ProductId
GROUP BY p.Id, p.Name
HAVING SUM(oi.Quantity) > 100
GO
DELETE FROM Products WHERE Quantity = 0 AND LastUpdated < DATEADD(month, -6, GETDATE())
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(5));
Assert.That(collection.RawStatements.Count, Is.EqualTo(5));
foreach (var statement in collection.RawStatements)
{
Assert.That(statement, Is.Not.Empty);
}
}
#endregion
#region Transaction Tests
[Test]
public void ParseBatch_WithTransactionStatements_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
BEGIN TRANSACTION UpdatePrices
UPDATE Products SET Price = Price * 1.1 WHERE Category = 'Electronics'
UPDATE ProductPriceHistory SET NewPrice = Price FROM Products WHERE Products.Id = ProductPriceHistory.ProductId
COMMIT TRANSACTION UpdatePrices
GO
BEGIN TRANSACTION DeleteOldOrders
DELETE FROM OrderItems WHERE OrderId IN (SELECT OrderId FROM Orders WHERE OrderDate < '2018-01-01')
DELETE FROM Orders WHERE OrderDate < '2018-01-01'
COMMIT TRANSACTION DeleteOldOrders
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.GreaterThanOrEqualTo(1));
var statement = collection.GetRawStatementAt(0);
Assert.That(statement, Does.Contain("BEGIN TRANSACTION"));
Assert.That(statement, Does.Contain("COMMIT"));
}
#endregion
#region Custom Separator Tests
[Test]
public void ParseBatch_WithSemicolonSeparator_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
SELECT * FROM Users
;
SELECT * FROM Orders
;
SELECT * FROM Products
";
// Act
collection.ParseBatch(batchSql, ";");
// Assert
Assert.That(collection.Count, Is.EqualTo(3));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("Users"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("Orders"));
Assert.That(collection.GetRawStatementAt(2), Does.Contain("Products"));
}
[Test]
public void ParseBatch_WithCustomSeparator_ParsesSuccessfully()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
INSERT INTO Users VALUES (1, 'John')
~~~
INSERT INTO Users VALUES (2, 'Jane')
~~~
INSERT INTO Users VALUES (3, 'Bob')
";
// Act
collection.ParseBatch(batchSql, "~~~");
// Assert
Assert.That(collection.Count, Is.EqualTo(3));
Assert.That(collection.RawStatements.Count, Is.EqualTo(3));
}
#endregion
#region Parameter Tests with CRUD
[Test]
public void ParseBatch_WithParameterizedInsertStatements_PreservesParameters()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
INSERT INTO Users (Id, Name, Email) VALUES (@UserId, @UserName, @UserEmail)
GO
INSERT INTO Orders (OrderId, UserId, OrderDate) VALUES (@OrderId, @UserId, @OrderDate)
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("@UserId"));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("@UserEmail"));
}
[Test]
public void ParseBatch_WithParameterizedUpdateStatements_PreservesParameters()
{
// Arrange
var collection = new SqlBreakdownCollection();
var batchSql = @"
UPDATE Users SET Name = @Name, Email = @Email WHERE Id = @UserId
GO
UPDATE Orders SET Status = @Status, ModifiedDate = @ModifiedDate WHERE OrderId = @OrderId
";
// Act
collection.ParseBatch(batchSql);
// Assert
Assert.That(collection.Count, Is.EqualTo(2));
Assert.That(collection.GetRawStatementAt(0), Does.Contain("@Name"));
Assert.That(collection.GetRawStatementAt(1), Does.Contain("@Status"));
}
[Test]
public void GetCombinedSql_WithMixedCrudOperations_CombinesCorrectly()
{
// Arrange
var collection = new SqlBreakdownCollection();
collection.ParseBatch(@"
INSERT INTO Users (Id, Name) VALUES (1, 'John')
GO
UPDATE Users SET Name = 'Jane' WHERE Id = 1
GO
DELETE FROM Users WHERE Id = 1
");
// Act
var combined = collection.GetCombinedSql();
// Assert
Assert.That(combined, Does.Contain("INSERT"));
Assert.That(combined, Does.Contain("UPDATE"));
Assert.That(combined, Does.Contain("DELETE"));
Assert.That(combined, Does.Contain("GO"));
}
#endregion
/// <summary>
/// Mock implementation of ISqlBreakdown for testing purposes.
/// </summary>
public class MockSqlBreakdown : ISqlBreakdown
{
private readonly string _sql;
public MockSqlBreakdown(string sql)
{
_sql = sql;
SetupClauses = new List<string>();
FinishClauses = new System.Collections.ArrayList();
}
public string? RawSql { get; set; }
public List<string> SetupClauses { get; set; }
public bool IsUsingSetupClause => SetupClauses.Count > 0;
public System.Collections.ArrayList FinishClauses { get; set; }
public bool IsUsingFinishClause => FinishClauses.Count > 0;
public string GetSql(bool includeSetupFinish = true)
{
var sb = new StringBuilder();
if (includeSetupFinish)
{
foreach (string setup in SetupClauses)
{
sb.AppendLine(setup);
}
}
sb.Append(_sql);
if (includeSetupFinish)
{
foreach (string finish in FinishClauses)
{
sb.AppendLine(finish);
}
}
return sb.ToString();
}
public override string ToString() => GetSql();
public object Clone()
{
var clone = (MockSqlBreakdown)MemberwiseClone();
clone.SetupClauses = new List<string>(SetupClauses);
clone.FinishClauses = new System.Collections.ArrayList(FinishClauses);
return clone;
}
}
}