Skip to content

Commit

Permalink
New "ignore errors" code and better ExtraInDatabase error
Browse files Browse the repository at this point in the history
  • Loading branch information
JonPSmith committed Nov 7, 2024
1 parent 74ebf0a commit 8884031
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 107 deletions.
72 changes: 3 additions & 69 deletions EfSchemaCompare/CompareLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,69 +175,6 @@ public static IEnumerable<string> ListAllErrors(IReadOnlyList<CompareLog> logs,
//-------------------------------------------------------
//internal

internal static CompareLog DecodeCompareTextToCompareLog(string str)
{
str = str.Trim();
var indexOfColon = str.IndexOf(':');
var indexOfArrow = str.IndexOf("->", StringComparison.Ordinal);
if (indexOfArrow < 0)
indexOfArrow = indexOfColon - 1;
var indexOfFirstQuote = str.IndexOf('\'');
var indexOfSecondQuote = str.Substring(indexOfFirstQuote + 1).IndexOf('\'') + indexOfFirstQuote + 1;

var state = (CompareState)Enum.Parse(typeof(CompareState), str.Substring(0, indexOfColon).Replace(" ", ""), true);
var type = (CompareType)Enum.Parse(typeof(CompareType), str.Substring(indexOfArrow + 2, indexOfFirstQuote - indexOfArrow - 3));
var name = str.Substring(indexOfFirstQuote + 1, indexOfSecondQuote - indexOfFirstQuote - 1);

var attribute = CompareAttributes.NotSet;
string expected = null;
string found = null;
if (str.Length - 1 > indexOfSecondQuote)
{
var charIndex = indexOfSecondQuote + 1;
//we have more information
if (str[charIndex] == ',')
{
var indexFullStop = str.Substring(charIndex).IndexOf('.') + charIndex; //warning, dot can be in name
attribute = (CompareAttributes)Enum.Parse(typeof(CompareAttributes),
str.Substring(charIndex + 1, indexFullStop - charIndex - 1).Replace(" ",""), true);
charIndex = indexFullStop;
}
if (str.StartsWith("EXTRA IN DATABASE"))
{
//Errors that have extra data

var foundIndex = str.IndexOf("Found = ");
if (foundIndex != -1)
{
//There is a found part
//EXAMPLE1: "EXTRA IN DATABASE: Table 'Customers', column name. Found = Contact"

type = CompareType.Column;
var startOfString = foundIndex + nameof(Expected).Length;
found = str.Substring(startOfString);
}
else
{
//EXAMPLE2: "EXTRA IN DATABASE: Database 'MyDatabase'"
type = CompareType.Table;
}

}
else if (str.Substring(charIndex).StartsWith(". Expected"))
{
//errors that expected something

var endCharIndex = str.Substring(charIndex + 3).IndexOf(", f");
endCharIndex = endCharIndex < 0 ? str.Length : endCharIndex + charIndex + 3;
var startOfString = charIndex + nameof(Expected).Length + 5;
expected = ReplaceNullTokenWithNull(str.Substring(startOfString, endCharIndex - startOfString));
}
}

return new CompareLog(type, state, name, attribute, expected, found);
}

internal bool ShouldIgnoreThisLog(IReadOnlyList<CompareLog> ignoreList)
{
return ignoreList.Any() && ignoreList.Any(ShouldBeIgnored);
Expand All @@ -254,8 +191,8 @@ private bool ShouldBeIgnored(CompareLog ignoreItem)
var result = (ignoreItem.Type == CompareType.MatchAnything || ignoreItem.Type == Type)
&& (ignoreItem.Attribute == CompareAttributes.MatchAnything || ignoreItem.Attribute == Attribute)
&& (ignoreItem.Name == null || ignoreItem.Name == Name)
&& (ignoreItem.Expected == null || ignoreItem.Expected == Expected)
&& (ignoreItem.Found == null || ignoreItem.Found == Found);
&& (ignoreItem.Expected == null || ignoreItem.Expected == Expected || ignoreItem.Expected == "<null>")
&& (ignoreItem.Found == null || ignoreItem.Found == Found || ignoreItem.Found == "<null>");

return result;
}
Expand All @@ -268,10 +205,7 @@ private static string ReplaceNullTokenWithNull(string str)
private string ToStringDifferentStart(string start)
{
//Typical output would be: Column 'Id', column type is Different : Expected = varchar(20), Found = nvarchar(20)
var type = Type == CompareType.Column && State == CompareState.ExtraInDatabase
? CompareType.Table
: Type;
var result = $"{start}{type} '{Name}'";
var result = $"{start}{Type} '{Name}'";
if (Attribute != CompareAttributes.NotSet)
result += $", {Attribute.SplitCamelCaseToLower()}";
if (State == CompareState.Ok)
Expand Down
22 changes: 17 additions & 5 deletions EfSchemaCompare/Internal/FindErrorsToIgnore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,20 @@ internal static CompareLog DecodeCompareTextToCompareLog(string errorString)

//These parts of the errors are the same in all the error pattern
var state = GetEnumType<CompareState>(errorString, null, ": ");
var attribute = GetEnumType<CompareAttributes>(errorString, " ,", ". ");
var attribute = GetEnumType<CompareAttributes>(errorString, ", ", ". ");

//string items. Some errors don't have Expected or Found, in which case it has null
var expected = GetStringInError(errorString, "Expected = ", null);
var found = GetStringInError(errorString, ". Found = ", null);
var name = GetStringInError(errorString, "'", "'");
//"Expected" can either have a "Found" after it, or not,
//so we get everything to the end and take off the "Found" part if it's there
var expected = GetStringInError(errorString, "Expected = ", null);
if (expected != null)
{
var possibleFoundStart = expected.IndexOf(", ", StringComparison.Ordinal);
if (possibleFoundStart> 0)
expected = expected.Substring(0, possibleFoundStart);
}
var found = GetStringInError(errorString, " found = ", null, true);

//The type part has two patterns
//1. "OK: DbContext ...", where "DbContext" is the type
Expand All @@ -46,14 +55,17 @@ internal static CompareLog DecodeCompareTextToCompareLog(string errorString)
/// <param name="errorString">A string containing an error created during </param>
/// <param name="beforeString">NOTE: If the beforeString is null/empty it will start at the first letter</param>
/// <param name="afterString">NOTE: If the beforeString is null/empty it will end it will go to the end </param>
/// <param name="ignoreCase">The 'found = ' can be 'found = ' or 'found = ', set this </param>
/// <returns>Returns the string between the two start/end strings.
/// NOTE: If either the beforeString or afterString aren't found it will return null, i.e. not found</returns>
private static string GetStringInError(string errorString, string beforeString, string afterString)
private static string GetStringInError(string errorString, string beforeString, string afterString, bool ignoreCase = false)
{
var typeStart = 0;
if (!String.IsNullOrEmpty(beforeString))
{
typeStart = errorString.IndexOf(beforeString) + beforeString.Length;
typeStart = errorString.IndexOf(beforeString,
ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)
+ beforeString.Length;
if (errorString.IndexOf(beforeString, StringComparison.Ordinal) == -1)
return null; //Could not find the beforeString
}
Expand Down
30 changes: 4 additions & 26 deletions Test/UnitTests/CompareLogsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,6 @@ public CompareLogsTests(ITestOutputHelper output)
_output = output;
}


[Fact]
public void Old_DecodeStringToCompareLog()
{
//SETUP
const string logOk = @"OK: DbContext 'BookContext'";
const string logStr1 =
@"NOT IN DATABASE: BookDetail->ForeignKey 'FK_Books_Books_BookSummaryId', constraint name. Expected = FK_Books_Books_BookSummaryId";
const string logStr2 =
@"DIFFERENT: BookSummary->Property 'BookSummaryId', value generated. Expected = OnAdd, found = Never";
const string logStr3 =
@"NOT IN DATABASE: BookDetail->ForeignKey 'FK_Books_Books_BookSummaryId', constraint name. Expected = FK_Books_Books_BookSummaryId";

//ATTEMPT

//VERIFY
CompareLog.DecodeCompareTextToCompareLog(logOk).ToString().ShouldEqual(logOk);
CompareLog.DecodeCompareTextToCompareLog(logStr1).ToString().ShouldEqual(logStr1.Replace("BookDetail->", ""));
CompareLog.DecodeCompareTextToCompareLog(logStr2).ToString().ShouldEqual(logStr2.Replace("BookSummary->", ""));
CompareLog.DecodeCompareTextToCompareLog(logStr3).ToString().ShouldEqual(logStr3.Replace("BookDetail->", ""));
}

[Fact]
public void DecodeCompareTextToCompareLog()
{
Expand All @@ -50,7 +28,8 @@ public void DecodeCompareTextToCompareLog()
const string logStr1 =
@"NOT IN DATABASE: BookDetail->ForeignKey 'FK_Books_Books_BookSummaryId', constraint name. Expected = FK_Books_Books_BookSummaryId";
const string logStr2 =
@"DIFFERENT: BookSummary->Property 'BookSummaryId', value generated. Expected = OnAdd, found = Never";
@"DIFFERENT: MyEntity->Property 'MyEntityId', value generated. Expected = Never, found = OnAdd";
//@"DIFFERENT: BookSummary->Property 'BookSummaryId', value generated. Expected = OnAdd, found = Never";
const string logStr3 =
@"NOT IN DATABASE: BookDetail->ForeignKey 'FK_Books_Books_BookSummaryId', constraint name. Expected = FK_Books_Books_BookSummaryId";

Expand All @@ -62,9 +41,8 @@ public void DecodeCompareTextToCompareLog()

//VERIFY
resultOk.ShouldEqual(logOk);
result1.ShouldEqual(logStr1.Replace("BookDetail->",""));
result2.ShouldEqual(
"DIFFERENT: Property 'BookSummaryId', value generated. Expected = OnAdd, found = <null>");
result1.ShouldEqual(logStr1.Replace("BookDetail->", ""));
result2.ShouldEqual(logStr2.Replace("MyEntity->", ""));
result3.ShouldEqual(logStr3.Replace("BookDetail->", ""));
}

Expand Down
2 changes: 1 addition & 1 deletion Test/UnitTests/Stage2ComparerMyEntityDiff.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void ExtrasProperty()
//VERIFY
hasErrors.ShouldBeTrue();
CompareLog.ListAllErrors(handler.Logs).Single().ShouldEqual(
"EXTRA IN DATABASE: Table 'MyEntites', column name. Found = MyEntityId");
"EXTRA IN DATABASE: Column 'MyEntites', column name. Found = MyEntityId");
}

[Fact]
Expand Down
2 changes: 1 addition & 1 deletion Test/UnitTests/TestComparerReadOnly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public void CompareReadOnlyDbContextExtraViewColumn()
hasErrors.ShouldBeTrue();
var errors = CompareLog.ListAllErrors(comparer.Logs).ToList();
(errors.Count == 1).ShouldBeTrue(comparer.GetAllErrors);
errors[0].ShouldEqual("EXTRA IN DATABASE: Table 'MyView', column name. Found = MyInt");
errors[0].ShouldEqual("EXTRA IN DATABASE: Column 'MyView', column name. Found = MyInt");
}


Expand Down
7 changes: 4 additions & 3 deletions Test/UnitTests/TestExtraInDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using DataLayer.BookApp.EfCode;
using EfSchemaCompare;
using EfSchemaCompare.Internal;
using TestSupport.EfHelpers;
using TestSupport.Helpers;
using Xunit;
Expand All @@ -24,7 +25,7 @@ public TestExtraInDatabase(ITestOutputHelper output)
public void DecodeCompareTextToCompareLog_ExtraIndexInDatabase_Test()
{
var str = "EXTRA IN DATABASE: Index 'tenants', index constraint name. Found = ix_tenants_belongs_to_database_instance_id";
var compareLog = CompareLog.DecodeCompareTextToCompareLog(str);
var compareLog = FindErrorsToIgnore.DecodeCompareTextToCompareLog(str);
compareLog.Type.ShouldEqual(CompareType.Index);
}

Expand Down Expand Up @@ -103,7 +104,7 @@ public void TestExtraColumn()
//VERIFY
hasErrors.ShouldBeTrue();
comparer.GetAllErrors.ShouldEqual(
"EXTRA IN DATABASE: Table 'Books', column name. Found = ExtraColumn");
"EXTRA IN DATABASE: Column 'Books', column name. Found = ExtraColumn");
}

[Fact]
Expand All @@ -124,7 +125,7 @@ public void TestExtraColumnIgnore()
TablesToIgnoreCommaDelimited = "",
};
config.IgnoreTheseErrors(
"EXTRA IN DATABASE: Table 'Books', column name. Found = ExtraColumn");
"EXTRA IN DATABASE: Column 'Books', column name. Found = ExtraColumn");
var comparer = new CompareEfSql(config);
var hasErrors = comparer.CompareEfWithDb(context);

Expand Down
4 changes: 2 additions & 2 deletions Test/UnitTests/TestJsonColumns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ public void CompareWithErrorsIgnored()

var config = new CompareEfSqlConfig();
//EXTRA IN DATABASE: Table 'HeadEntries', column name. Found = DifferentColumnName
config.IgnoreTheseErrors("EXTRA IN DATABASE: Table 'HeadEntries', column name. Found = DifferentColumnName");
config.IgnoreTheseErrors("EXTRA IN DATABASE: Column 'HeadEntries', column name. Found = DifferentColumnName");

var comparer = new CompareEfSql(config);

Expand Down Expand Up @@ -236,7 +236,7 @@ public void CompareWithNoIgnores()
//VERIFY
//Just print errors
hasErrors.ShouldBeTrue();
comparer.GetAllErrors.ShouldEqual("EXTRA IN DATABASE: Table 'HeadEntries', column name. Found = DifferentColumnName");
comparer.GetAllErrors.ShouldEqual("EXTRA IN DATABASE: Column 'HeadEntries', column name. Found = DifferentColumnName");
_output.WriteLine(comparer.GetAllErrors);
}
}

0 comments on commit 8884031

Please sign in to comment.