chore: initial git load of code space

This commit is contained in:
Thom Lamb
2026-05-12 08:52:33 -05:00
parent 9abada692f
commit 5e467bcc9c
384 changed files with 65960 additions and 2 deletions
@@ -0,0 +1,682 @@
using NUnit.Framework;
using Strata.SqlTools.Builders.LinqToSql;
using Strata.SqlTools.Comparers.LinqToSql;
namespace Strata.SqlTools.LinqToSql.Tests;
[TestFixture]
public class QueryComparatorTests
{
#region Equivalence Tests
[Test]
public void AreEquivalent_WithIdenticalQueries_ReturnsTrue()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Where("IsActive = true")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Where("IsActive = true")
.Build();
// Act
var comparator = QueryComparator.Compare(query1, query2);
// Assert
Assert.That(comparator.AreEquivalent, Is.True);
}
[Test]
public void AreEquivalent_WithDifferentSelectClauses_ReturnsFalse()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name", "Email")
.FromTable("Users")
.Build();
// Act
var comparator = QueryComparator.Compare(query1, query2);
// Assert
Assert.That(comparator.AreEquivalent, Is.False);
}
[Test]
public void AreEquivalent_WithDifferentFromClauses_ReturnsFalse()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Customers")
.Build();
// Act
var comparator = QueryComparator.Compare(query1, query2);
// Assert
Assert.That(comparator.AreEquivalent, Is.False);
}
[Test]
public void AreEquivalent_WithDifferentWhereClauses_ReturnsFalse()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Where("Age > 18")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Where("Age > 21")
.Build();
// Act
var comparator = QueryComparator.Compare(query1, query2);
// Assert
Assert.That(comparator.AreEquivalent, Is.False);
}
[Test]
public void AreEquivalent_WithWhitespaceVariations_ReturnsTrue()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
// Act
var comparator = QueryComparator.Compare(query1, query2);
// Assert
Assert.That(comparator.AreEquivalent, Is.True);
}
#endregion
#region Similarity Score Tests
[Test]
public void SimilarityScore_WithIdenticalQueries_ReturnsOne()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Where("IsActive = true")
.OrderByAscending("Name")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Where("IsActive = true")
.OrderByAscending("Name")
.Build();
// Act
var score = QueryComparator.GetSimilarity(query1, query2);
// Assert
Assert.That(score, Is.EqualTo(1.0));
}
[Test]
public void SimilarityScore_WithPartialMatch_ReturnsBetweenZeroAndOne()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Where("IsActive = true")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Where("IsActive = false")
.Build();
// Act
var score = QueryComparator.GetSimilarity(query1, query2);
// Assert
Assert.That(score, Is.GreaterThan(0.0));
Assert.That(score, Is.LessThan(1.0));
}
[Test]
public void SimilarityScore_WithCompletelyDifferentQueries_ReturnsLow()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id")
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("OrderId")
.FromTable("Orders")
.Build();
// Act
var score = QueryComparator.GetSimilarity(query1, query2);
// Assert
// Only SELECT and FROM different, rest are same (empty), so ~67% match
Assert.That(score, Is.LessThan(0.75));
Assert.That(score, Is.GreaterThan(0.5));
}
#endregion
#region Difference Detection Tests
[Test]
public void Differences_WithMultipleDifferences_ListsAll()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Where("Active = true")
.GroupBy("Department")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id")
.FromTable("Orders")
.Build();
// Act
var comparator = QueryComparator.Compare(query1, query2);
// Assert
Assert.That(comparator.Differences.Count, Is.GreaterThan(2));
Assert.That(comparator.Differences, Does.Contain("SELECT clauses differ"));
Assert.That(comparator.Differences, Does.Contain("FROM clauses differ"));
}
[Test]
public void Differences_WithNoDifferences_IsEmpty()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
// Act
var comparator = QueryComparator.Compare(query1, query2);
// Assert
Assert.That(comparator.Differences, Is.Empty);
}
#endregion
#region Clause-Specific Comparison Tests
[Test]
public void Compare_TrackSelectClauseMatch()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Build();
// Act
var result = QueryComparator.Compare(query1, query2).Result;
// Assert
Assert.That(result.HaveSameSelectColumns, Is.True);
}
[Test]
public void Compare_TrackFromClauseMatch()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
// Act
var result = QueryComparator.Compare(query1, query2).Result;
// Assert
Assert.That(result.HaveSameFromTable, Is.True);
}
[Test]
public void Compare_TrackWhereClauseMatch()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Where("IsActive = true")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Where("IsActive = true")
.Build();
// Act
var result = QueryComparator.Compare(query1, query2).Result;
// Assert
Assert.That(result.HaveSameWhereClause, Is.True);
}
[Test]
public void Compare_TrackGroupByClauseMatch()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Department", "COUNT(*)")
.FromTable("Employees")
.GroupBy("Department")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Department", "COUNT(*)")
.FromTable("Employees")
.GroupBy("Department")
.Build();
// Act
var result = QueryComparator.Compare(query1, query2).Result;
// Assert
Assert.That(result.HaveSameGroupBy, Is.True);
}
[Test]
public void Compare_TrackHavingClauseMatch()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Department", "COUNT(*)")
.FromTable("Employees")
.GroupBy("Department")
.Having("COUNT(*) > 5")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Department", "COUNT(*)")
.FromTable("Employees")
.GroupBy("Department")
.Having("COUNT(*) > 5")
.Build();
// Act
var result = QueryComparator.Compare(query1, query2).Result;
// Assert
Assert.That(result.HaveSameHaving, Is.True);
}
[Test]
public void Compare_TrackOrderByClauseMatch()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.OrderByDescending("CreatedDate")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.OrderByDescending("CreatedDate")
.Build();
// Act
var result = QueryComparator.Compare(query1, query2).Result;
// Assert
Assert.That(result.HaveSameOrderBy, Is.True);
}
#endregion
#region Static Factory Method Tests
[Test]
public void AreQueriesEquivalent_StaticMethod_ReturnsCorrectValue()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
// Act
var result = QueryComparator.AreQueriesEquivalent(query1, query2);
// Assert
Assert.That(result, Is.True);
}
[Test]
public void AreQueriesIdentical_WithIdenticalQueries_ReturnsTrue()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Build();
// Act
var result = QueryComparator.AreQueriesIdentical(query1, query2);
// Assert
Assert.That(result, Is.True);
}
[Test]
public void AreQueriesIdentical_WithSimilarQueries_ReturnsFalse()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name", "Email")
.FromTable("Users")
.Build();
// Act
var result = QueryComparator.AreQueriesIdentical(query1, query2);
// Assert
Assert.That(result, Is.False);
}
[Test]
public void GetSimilarity_StaticMethod_ReturnsCorrectScore()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
// Act
var score = QueryComparator.GetSimilarity(query1, query2);
// Assert
Assert.That(score, Is.EqualTo(1.0));
}
#endregion
#region Null Handling Tests
[Test]
public void Constructor_WithNullQuery1_ThrowsArgumentNullException()
{
// Arrange
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
// Act & Assert
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
Assert.Throws<ArgumentNullException>(() => new QueryComparator(null, query2));
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
}
[Test]
public void Constructor_WithNullQuery2_ThrowsArgumentNullException()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
// Act & Assert
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
Assert.Throws<ArgumentNullException>(() => new QueryComparator(query1, null));
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
}
#endregion
#region Report Generation Tests
[Test]
public void GetReport_WithIdenticalQueries_ShowsIdentical()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
// Act
var comparator = QueryComparator.Compare(query1, query2);
var report = comparator.Result.GetReport();
// Assert
Assert.That(report, Contains.Substring("identical"));
}
[Test]
public void GetReport_WithDifferentQueries_ListsDifferences()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id")
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectColumns("Id", "Name")
.FromTable("Orders")
.Build();
// Act
var comparator = QueryComparator.Compare(query1, query2);
var report = comparator.Result.GetReport();
// Assert
Assert.That(report, Contains.Substring("Differences"));
Assert.That(report, Contains.Substring("SELECT clauses differ"));
Assert.That(report, Contains.Substring("FROM clauses differ"));
}
[Test]
public void GetReport_IncludesSimilarityScore()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Orders")
.Build();
// Act
var comparator = QueryComparator.Compare(query1, query2);
var report = comparator.Result.GetReport();
// Assert
Assert.That(report, Contains.Substring("Similarity: "));
}
#endregion
#region Edge Cases
[Test]
public void CompareWithEmptyQueriesStillWorks()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
// Act
var result = QueryComparator.AreQueriesEquivalent(query1, query2);
// Assert
Assert.That(result, Is.True);
}
[Test]
public void SimilarityScore_IsBoundedBetweenZeroAndOne()
{
// Arrange
var query1 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Users")
.Build();
var query2 = LinqQueryBreakdownBuilder
.Create()
.SelectAll()
.FromTable("Orders")
.Build();
// Act
var score = QueryComparator.GetSimilarity(query1, query2);
// Assert
Assert.That(score, Is.GreaterThanOrEqualTo(0.0));
Assert.That(score, Is.LessThanOrEqualTo(1.0));
}
#endregion
}