diff --git a/src/grate.core/Infrastructure/BatchSplitterReplacer.cs b/src/grate.core/Infrastructure/BatchSplitterReplacer.cs deleted file mode 100644 index cb571314..00000000 --- a/src/grate.core/Infrastructure/BatchSplitterReplacer.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Text.RegularExpressions; -using static System.Text.RegularExpressions.RegexOptions; - -namespace grate.Infrastructure; - -internal class BatchSplitterReplacer -{ - private string Replacement { get; } - private readonly Regex _regex; - - public BatchSplitterReplacer(ISyntax syntax) - { - var pattern = syntax.StatementSeparatorRegex; - Replacement = StatementSplitter.BatchTerminatorReplacementString; - - _regex = new Regex(pattern, IgnoreCase | Multiline); - } - - public string Replace(string text) => _regex.Replace(text, ReplaceBatchSeparator); - - private string ReplaceBatchSeparator(Match match) - { - var groups = match.Groups; - var replacement = groups["BATCHSPLITTER"].Success ? Replacement : string.Empty; - return groups["KEEP1"].Value + replacement + groups["KEEP2"].Value; - } -} diff --git a/src/grate.core/Infrastructure/IStatementSplitter.cs b/src/grate.core/Infrastructure/IStatementSplitter.cs new file mode 100644 index 00000000..7426cda0 --- /dev/null +++ b/src/grate.core/Infrastructure/IStatementSplitter.cs @@ -0,0 +1,9 @@ +namespace grate.Infrastructure; + +/// +/// Splits a batch of SQL text into individual statements to be run separately. +/// +public interface IStatementSplitter +{ + IEnumerable Split(string statement); +} diff --git a/src/grate.core/Infrastructure/ISyntax.cs b/src/grate.core/Infrastructure/ISyntax.cs index 7343e2d4..6b973484 100644 --- a/src/grate.core/Infrastructure/ISyntax.cs +++ b/src/grate.core/Infrastructure/ISyntax.cs @@ -5,7 +5,7 @@ /// public interface ISyntax { - string StatementSeparatorRegex { get; } + IStatementSplitter StatementSplitter { get; } string CurrentDatabase { get; } string ListDatabases { get; } string CreateDatabase(string databaseName, string? password); diff --git a/src/grate.core/Infrastructure/RegexStatementSplitter.cs b/src/grate.core/Infrastructure/RegexStatementSplitter.cs new file mode 100644 index 00000000..13cf6dcc --- /dev/null +++ b/src/grate.core/Infrastructure/RegexStatementSplitter.cs @@ -0,0 +1,59 @@ +using System.Text.RegularExpressions; +using static System.Text.RegularExpressions.RegexOptions; + +namespace grate.Infrastructure; + +/// +/// Base class for splitting SQL batches into statements using a dialect-specific regex. +/// The regex must tag the parts to keep as KEEP1/KEEP2 groups, and the separator to remove as BATCHSPLITTER. +/// +public abstract class RegexStatementSplitter : IStatementSplitter +{ + private const string BatchTerminatorReplacementString = @" |{[_REMOVE_]}| "; + + protected abstract string StringsRegex { get; } + protected abstract string DashCommentsRegex { get; } + protected abstract string StarCommentsRegex { get; } + protected abstract string SeparatorRegex { get; } + + /// + /// Additional regex fragments to be inserted between the strings and comments patterns (e.g. for extra string forms). + /// + protected virtual IEnumerable AdditionalRegexes => Enumerable.Empty(); + + private Regex? _regex; + private Regex Regex => _regex ??= new Regex(Pattern, IgnoreCase | Multiline); + + private string Pattern => + string.Join("|", new[] { StringsRegex } + .Concat(AdditionalRegexes) + .Append(DashCommentsRegex) + .Append(StarCommentsRegex) + .Append(SeparatorRegex)); + + public IEnumerable Split(string statement) + { + var replaced = Replace(statement); + + var statements = replaced.Split(BatchTerminatorReplacementString); + return statements.Where(HasScriptsToRun); + } + + private string Replace(string text) => Regex.Replace(text, ReplaceBatchSeparator); + + private static string ReplaceBatchSeparator(Match match) + { + var groups = match.Groups; + var replacement = groups["BATCHSPLITTER"].Success ? BatchTerminatorReplacementString : string.Empty; + return groups["KEEP1"].Value + replacement + groups["KEEP2"].Value; + } + + private static bool HasScriptsToRun(string sqlStatement) + { + var trimmedStatement = sqlStatement.Replace(BatchTerminatorReplacementString, string.Empty, StringComparison.InvariantCultureIgnoreCase); + return !string.IsNullOrEmpty(trimmedStatement.ToLower() + .Replace(Environment.NewLine, string.Empty) + .Replace("\n", string.Empty) // This is necessary to make script with unix-style line endings work on grate on Windows + .Replace(" ", string.Empty)); + } +} diff --git a/src/grate.core/Infrastructure/StatementSplitter.cs b/src/grate.core/Infrastructure/StatementSplitter.cs deleted file mode 100644 index 91c88134..00000000 --- a/src/grate.core/Infrastructure/StatementSplitter.cs +++ /dev/null @@ -1,33 +0,0 @@ -using grate.Migration; - -namespace grate.Infrastructure; - -internal class StatementSplitter -{ - public const string BatchTerminatorReplacementString = @" |{[_REMOVE_]}| "; - - private readonly BatchSplitterReplacer _replacer; - - public StatementSplitter(ISyntax syntax) - { - _replacer = new BatchSplitterReplacer(syntax); - } - - public IEnumerable Split(string statement) - { - var replaced = _replacer.Replace(statement); - - var statements = replaced.Split(BatchTerminatorReplacementString); - return statements.Where(HasScriptsToRun); - } - - private static bool HasScriptsToRun(string sqlStatement) - { - var trimmedStatement = sqlStatement.Replace(BatchTerminatorReplacementString, string.Empty, StringComparison.InvariantCultureIgnoreCase); - return !string.IsNullOrEmpty(trimmedStatement.ToLower() - .Replace(Environment.NewLine, string.Empty) - .Replace("\n", string.Empty) // This is necessary to make script with unix-style line endings work on grate on Windows - .Replace(" ", string.Empty)); - } - -} diff --git a/src/grate.core/Migration/AnsiSqlDatabase.cs b/src/grate.core/Migration/AnsiSqlDatabase.cs index 84362e2a..b18596fc 100644 --- a/src/grate.core/Migration/AnsiSqlDatabase.cs +++ b/src/grate.core/Migration/AnsiSqlDatabase.cs @@ -36,7 +36,6 @@ protected AnsiSqlDatabase(ILogger logger, ISyntax syntax) { Logger = logger; _syntax = syntax; - StatementSplitter = new StatementSplitter(syntax); } public string ServerName => Connection.DataSource; @@ -54,15 +53,13 @@ protected AnsiSqlDatabase(ILogger logger, ISyntax syntax) public abstract bool SupportsSchemas { get; } public virtual bool SplitBatchStatements => true; - private StatementSplitter StatementSplitter { get; } + private IStatementSplitter StatementSplitter => _syntax.StatementSplitter; public virtual IEnumerable GetStatements(string sql) => SplitBatchStatements ? this.StatementSplitter.Split(sql) : new[] { sql }; public abstract void ThrowScriptFailed(MigrationsFolder folder, string file, string? scriptText, Exception exception); - public string StatementSeparatorRegex => _syntax.StatementSeparatorRegex; - public string ScriptsRunTable => _syntax.TableWithSchema(SchemaName, ScriptsRunTableName); public string ScriptsRunErrorsTable => _syntax.TableWithSchema(SchemaName, ScriptsRunErrorsTableName); public string VersionTable => _syntax.TableWithSchema(SchemaName, VersionTableName); diff --git a/src/grate.mariadb/Infrastructure/MariaDbStatementSplitter.cs b/src/grate.mariadb/Infrastructure/MariaDbStatementSplitter.cs new file mode 100644 index 00000000..99c1acb6 --- /dev/null +++ b/src/grate.mariadb/Infrastructure/MariaDbStatementSplitter.cs @@ -0,0 +1,11 @@ +using grate.Infrastructure; + +namespace grate.MariaDb.Infrastructure; + +public class MariaDbStatementSplitter : RegexStatementSplitter +{ + protected override string StringsRegex => @"(?'[^']*')"; + protected override string DashCommentsRegex => @"(?--.*$)"; + protected override string StarCommentsRegex => @"(?/\*[\S\s]*?\*/)"; + protected override string SeparatorRegex => @"(?^|\s)(?GO)(?\s|;|$)"; +} diff --git a/src/grate.mariadb/Infrastructure/MariaDbSyntax.cs b/src/grate.mariadb/Infrastructure/MariaDbSyntax.cs index 5909ecb7..0c739325 100644 --- a/src/grate.mariadb/Infrastructure/MariaDbSyntax.cs +++ b/src/grate.mariadb/Infrastructure/MariaDbSyntax.cs @@ -3,17 +3,8 @@ namespace grate.MariaDb.Infrastructure; public readonly struct MariaDbSyntax : ISyntax { - public string StatementSeparatorRegex - { - get - { - const string strings = @"(?'[^']*')"; - const string dashComments = @"(?--.*$)"; - const string starComments = @"(?/\*[\S\s]*?\*/)"; - const string separator = @"(?^|\s)(?GO)(?\s|;|$)"; - return strings + "|" + dashComments + "|" + starComments + "|" + separator; - } - } + private static readonly IStatementSplitter _statementSplitter = new MariaDbStatementSplitter(); + public IStatementSplitter StatementSplitter => _statementSplitter; public string CurrentDatabase => "SELECT DATABASE()"; public string ListDatabases => "SHOW DATABASES"; diff --git a/src/grate.oracle/Infrastructure/OracleStatementSplitter.cs b/src/grate.oracle/Infrastructure/OracleStatementSplitter.cs new file mode 100644 index 00000000..b04692d6 --- /dev/null +++ b/src/grate.oracle/Infrastructure/OracleStatementSplitter.cs @@ -0,0 +1,11 @@ +using grate.Infrastructure; + +namespace grate.Oracle.Infrastructure; + +public class OracleStatementSplitter : RegexStatementSplitter +{ + protected override string StringsRegex => @"(?'[^']*')"; + protected override string DashCommentsRegex => @"(?--.*$)"; + protected override string StarCommentsRegex => @"(?/\*[\S\s]*?\*/)"; + protected override string SeparatorRegex => @"(?^|\s)(?/)(?\s|;|$)"; +} diff --git a/src/grate.oracle/Infrastructure/OracleSyntax.cs b/src/grate.oracle/Infrastructure/OracleSyntax.cs index b4463d58..cd85873b 100644 --- a/src/grate.oracle/Infrastructure/OracleSyntax.cs +++ b/src/grate.oracle/Infrastructure/OracleSyntax.cs @@ -4,17 +4,8 @@ namespace grate.Oracle.Infrastructure; public readonly struct OracleSyntax : ISyntax { - public string StatementSeparatorRegex - { - get - { - const string strings = @"(?'[^']*')"; - const string dashComments = @"(?--.*$)"; - const string starComments = @"(?/\*[\S\s]*?\*/)"; - const string separator = @"(?^|\s)(?/)(?\s|;|$)"; - return strings + "|" + dashComments + "|" + starComments + "|" + separator; - } - } + private static readonly IStatementSplitter _statementSplitter = new OracleStatementSplitter(); + public IStatementSplitter StatementSplitter => _statementSplitter; public string CurrentDatabase => "select user from dual"; public string ListDatabases => "SELECT * FROM all_users"; diff --git a/src/grate.postgresql/Infrastructure/PostgreSqlStatementSplitter.cs b/src/grate.postgresql/Infrastructure/PostgreSqlStatementSplitter.cs new file mode 100644 index 00000000..19ea814f --- /dev/null +++ b/src/grate.postgresql/Infrastructure/PostgreSqlStatementSplitter.cs @@ -0,0 +1,22 @@ +using grate.Infrastructure; + +namespace grate.PostgreSql.Infrastructure; + +public class PostgreSqlStatementSplitter : RegexStatementSplitter +{ + protected override string StringsRegex => @"(?'([^']|\'\')*')"; + protected override string DashCommentsRegex => "(?--.*$)"; + protected override string StarCommentsRegex => @"(?/\*[\S\s]*?\*/)"; + protected override string SeparatorRegex => "(?.*)(?(;)(?=(?:[^']|'[^']*')*$))(?.*)"; + + protected override IEnumerable AdditionalRegexes + { + get + { + const string backslashEscapedStrings = @"(?E(?\$(?'tag'\w*)\$[\S\s]*?\$\k'tag'\$)"; + yield return backslashEscapedStrings; + yield return dollarQuotedStrings; + } + } +} diff --git a/src/grate.postgresql/Infrastructure/PostgreSqlSyntax.cs b/src/grate.postgresql/Infrastructure/PostgreSqlSyntax.cs index 78c8ad73..d86008b6 100644 --- a/src/grate.postgresql/Infrastructure/PostgreSqlSyntax.cs +++ b/src/grate.postgresql/Infrastructure/PostgreSqlSyntax.cs @@ -3,19 +3,8 @@ namespace grate.PostgreSql.Infrastructure; public readonly struct PostgreSqlSyntax : ISyntax { - public string StatementSeparatorRegex - { - get - { - const string strings = @"(?'([^']|\'\')*')"; - const string backslashEscapedStrings = @"(?E(?\$(?'tag'\w*)\$[\S\s]*?\$\k'tag'\$)"; - const string dashComments = "(?--.*$)"; - const string starComments = @"(?/\*[\S\s]*?\*/)"; - const string separator = "(?.*)(?(;)(?=(?:[^']|'[^']*')*$))(?.*)"; - return strings + "|" + backslashEscapedStrings + "|" + dollarQuotedStrings + "|" + dashComments + "|" + starComments + "|" + separator; - } - } + private static readonly IStatementSplitter _statementSplitter = new PostgreSqlStatementSplitter(); + public IStatementSplitter StatementSplitter => _statementSplitter; public string CurrentDatabase => "SELECT current_database()"; public string ListDatabases => "SELECT datname FROM pg_database"; diff --git a/src/grate.sqlite/Infrastructure/SqliteStatementSplitter.cs b/src/grate.sqlite/Infrastructure/SqliteStatementSplitter.cs new file mode 100644 index 00000000..27bbf153 --- /dev/null +++ b/src/grate.sqlite/Infrastructure/SqliteStatementSplitter.cs @@ -0,0 +1,11 @@ +using grate.Infrastructure; + +namespace grate.Sqlite.Infrastructure; + +public class SqliteStatementSplitter : RegexStatementSplitter +{ + protected override string StringsRegex => @"(?'[^']*')"; + protected override string DashCommentsRegex => @"(?--.*$)"; + protected override string StarCommentsRegex => @"(?/\*[\S\s]*?\*/)"; + protected override string SeparatorRegex => @"(?^|\s)(?GO)(?\s|;|$)"; +} diff --git a/src/grate.sqlite/Infrastructure/SqliteSyntax.cs b/src/grate.sqlite/Infrastructure/SqliteSyntax.cs index 9b80b95e..ccfe1d6b 100644 --- a/src/grate.sqlite/Infrastructure/SqliteSyntax.cs +++ b/src/grate.sqlite/Infrastructure/SqliteSyntax.cs @@ -3,17 +3,8 @@ namespace grate.Sqlite.Infrastructure; public readonly struct SqliteSyntax : ISyntax { - public string StatementSeparatorRegex - { - get - { - const string strings = @"(?'[^']*')"; - const string dashComments = @"(?--.*$)"; - const string starComments = @"(?/\*[\S\s]*?\*/)"; - const string separator = @"(?^|\s)(?GO)(?\s|;|$)"; - return strings + "|" + dashComments + "|" + starComments + "|" + separator; - } - } + private static readonly IStatementSplitter _statementSplitter = new SqliteStatementSplitter(); + public IStatementSplitter StatementSplitter => _statementSplitter; public string CurrentDatabase => "SELECT name FROM pragma_database_list ORDER BY seq DESC LIMIT 1"; public string ListDatabases => "select name from pragma_database_list"; diff --git a/src/grate.sqlserver/Infrastructure/SqlServerStatementSplitter.cs b/src/grate.sqlserver/Infrastructure/SqlServerStatementSplitter.cs new file mode 100644 index 00000000..3cc2a494 --- /dev/null +++ b/src/grate.sqlserver/Infrastructure/SqlServerStatementSplitter.cs @@ -0,0 +1,126 @@ +using System.Diagnostics; +using System.Text.RegularExpressions; +using grate.Infrastructure; + +namespace grate.SqlServer.Infrastructure; + +/// +/// Splits SQL Server batches on GO separators using a tokenizer rather than a single regex, +/// so nested comments, string literals and batch separators can be mixed in any combination. +/// +public partial class SqlServerStatementSplitter : IStatementSplitter +{ + private enum TokenType + { + BatchSeparator, + StringDelimiter, + MultiLineCommentStart, + MultiLineCommentEnd, + SingleLineCommentStart, + NewLine + } + + private readonly record struct Token(TokenType Type, int Index, int Length); + + [GeneratedRegex( + """ + \bGO\b|'|/\*|\*/|--|$ + """, + RegexOptions.Multiline | RegexOptions.IgnoreCase)] + private static partial Regex TokenPattern(); + + [GeneratedRegex(@"\S")] + private static partial Regex SignificantTextPattern(); + + public IEnumerable Split(string statement) => + BreakIntoBatches(statement).Where(batch => SignificantTextPattern().IsMatch(batch)); + + private static IEnumerable Tokenize(string sql) + { + for (var match = TokenPattern().Match(sql); match.Success; match = match.NextMatch()) + { + // Each alternative in TokenPattern yields distinct literal text, so the matched + // value alone identifies the token type - anything else is the (case-insensitive) GO. + var type = match.Value switch + { + "'" => TokenType.StringDelimiter, + "/*" => TokenType.MultiLineCommentStart, + "*/" => TokenType.MultiLineCommentEnd, + "--" => TokenType.SingleLineCommentStart, + "" => TokenType.NewLine, + _ => TokenType.BatchSeparator + }; + yield return new Token(type, match.Index, match.Length); + } + } + + /// + /// Cuts the sql into batches wherever a GO batch separator token is found outside + /// of any string literal or comment, tracking nested multi-line comments. + /// + private static IEnumerable BreakIntoBatches(string sql) + { + using var tokens = Tokenize(sql).GetEnumerator(); + var cutIndex = 0; + var token = default(Token); + + bool NextToken() + { + if (!tokens.MoveNext()) + { + return false; + } + token = tokens.Current; + return true; + } + + while (NextToken()) + { + switch (token.Type) + { + case TokenType.BatchSeparator: + // great! we have a batch of SQL. + yield return sql[cutIndex..token.Index]; + cutIndex = token.Index + token.Length; + break; + + case TokenType.StringDelimiter: + // Consume until we exit the string + while (NextToken() && token.Type != TokenType.StringDelimiter) + { + } + break; + + case TokenType.MultiLineCommentStart: + // Consume until we exit the top-most comment, + // accounting for nesting + var depth = 1; + while (depth > 0 && NextToken()) + { + depth += token.Type switch + { + TokenType.MultiLineCommentStart => 1, + TokenType.MultiLineCommentEnd => -1, + _ => 0 + }; + } + break; + + case TokenType.SingleLineCommentStart: + while (NextToken() && token.Type != TokenType.NewLine) + { + } + break; + + case TokenType.NewLine: + break; + + default: + throw new UnreachableException($"Unexpected token type: {token.Type}"); + } + } + + // And the final sql batch + yield return sql[cutIndex..]; + } +} diff --git a/src/grate.sqlserver/Infrastructure/SqlServerSyntax.cs b/src/grate.sqlserver/Infrastructure/SqlServerSyntax.cs index a8ec4a5f..65106c2d 100644 --- a/src/grate.sqlserver/Infrastructure/SqlServerSyntax.cs +++ b/src/grate.sqlserver/Infrastructure/SqlServerSyntax.cs @@ -3,17 +3,8 @@ namespace grate.SqlServer.Infrastructure; public readonly struct SqlServerSyntax : ISyntax { - public string StatementSeparatorRegex - { - get - { - const string strings = @"(?'[^']*')"; - const string dashComments = @"(?--.*$)"; - const string starComments = @"(?/\*[\S\s]*?\*/)"; - const string separator = @"(?^|\s)(?GO)(?\s|;|$)"; - return strings + "|" + dashComments + "|" + starComments + "|" + separator; - } - } + private static readonly IStatementSplitter _statementSplitter = new SqlServerStatementSplitter(); + public IStatementSplitter StatementSplitter => _statementSplitter; public string CurrentDatabase => "SELECT DB_NAME()"; public string ListDatabases => "SELECT name FROM sys.databases"; diff --git a/unittests/Oracle/Basic_tests/BatchSplitterReplacer_.cs b/unittests/Oracle/Basic_tests/BatchSplitterReplacer_.cs deleted file mode 100644 index df240446..00000000 --- a/unittests/Oracle/Basic_tests/BatchSplitterReplacer_.cs +++ /dev/null @@ -1,580 +0,0 @@ -using grate.Infrastructure; -using grate.Migration; -using grate.Oracle.Infrastructure; -using Oracle.TestInfrastructure; - -// ReSharper disable InconsistentNaming - -namespace Oracle.Basic_tests; - - -public class BatchSplitterReplacer_ -{ - private const string Batch_terminator_replacement_string = StatementSplitter.BatchTerminatorReplacementString; - - private const string Symbols_to_check = "`~!@#$%^&*()-_+=,.;:'\"[]\\/?<>"; - private const string Words_to_check = "abcdefghijklmnopqrstuvwzyz0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - // private static readonly IDatabase Database = new OracleDatabase(NullLogger.Instance); - - // private static BatchSplitterReplacer Replacer => new(Database.StatementSeparatorRegex, StatementSplitter.BatchTerminatorReplacementString); - - // ReSharper disable once InconsistentNaming - public class should_replace_on - { - private ITestOutputHelper _testOutput; - private BatchSplitterReplacer Replacer; - - public should_replace_on(ITestOutputHelper testOutput) - { - _testOutput = testOutput; - Replacer = new BatchSplitterReplacer(new OracleSyntax()); - } - - [Fact] - public void full_statement_without_issue() - { - string sql_to_match = OracleSplitterContext.FullSplitter.PLSqlStatement; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(OracleSplitterContext.FullSplitter.PLSqlStatementScrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_space() - { - const string sql_to_match = @" / "; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" "; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_tab() - { - string sql_to_match = @" /" + "\t"; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + "\t"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_by_itself() - { - const string sql_to_match = @"/"; - string expected_scrubbed = Batch_terminator_replacement_string; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_starting_file() - { - const string sql_to_match = @"/ -whatever"; - string expected_scrubbed = Batch_terminator_replacement_string + @" -whatever"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_new_line() - { - const string sql_to_match = @" / -"; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_one_new_line_after_double_dash_comments() - { - const string sql_to_match = - @"-- -/ -"; - string expected_scrubbed = - @"-- -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_one_new_line_after_double_dash_comments_and_words() - { - string sql_to_match = @"-- " + Words_to_check + @" -/ -"; - string expected_scrubbed = @"-- " + Words_to_check + @" -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_new_line_after_double_dash_comments_and_symbols() - { - string sql_to_match = @"-- " + Symbols_to_check + @" -/ -"; - string expected_scrubbed = @"-- " + Symbols_to_check + @" -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_on_its_own_line() - { - const string sql_to_match = @" -/ -"; - string expected_scrubbed = @" -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_no_line_terminator() - { - const string sql_to_match = @" / "; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" "; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_words_before() - { - string sql_to_match = Words_to_check + @" / -"; - string expected_scrubbed = Words_to_check + @" " + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_symbols_and_words_before() - { - string sql_to_match = Symbols_to_check + Words_to_check + @" / -"; - string expected_scrubbed = Symbols_to_check + Words_to_check + @" " + - Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_words_and_symbols_before() - { - string sql_to_match = Words_to_check + Symbols_to_check + @" / -"; - string expected_scrubbed = Words_to_check + Symbols_to_check + @" " + - Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_words_after_on_the_same_line() - { - string sql_to_match = @" / " + Words_to_check; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" " + Words_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_words_after_on_the_same_line_including_symbols() - { - string sql_to_match = @" / " + Words_to_check + Symbols_to_check; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" " + Words_to_check + - Symbols_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_words_before_and_after_on_the_same_line() - { - string sql_to_match = Words_to_check + @" / " + Words_to_check; - string expected_scrubbed = Words_to_check + @" " + Batch_terminator_replacement_string + @" " + - Words_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_words_before_and_after_on_the_same_line_including_symbols() - { - string sql_to_match = Words_to_check + Symbols_to_check.Replace("'", "").Replace("\"", "") + - " / BOB" + Symbols_to_check; - string expected_scrubbed = Words_to_check + Symbols_to_check.Replace("'", "").Replace("\"", "") + - " " + Batch_terminator_replacement_string + " BOB" + Symbols_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_after_double_dash_comment_with_single_quote_and_single_quote_after_slash() - { - string sql_to_match = Words_to_check + @" -- ' -/ -select '' -/"; - string expected_scrubbed = Words_to_check + @" -- ' -" + Batch_terminator_replacement_string + @" -select '' -" + Batch_terminator_replacement_string; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_comment_after() - { - string sql_to_match = " / -- comment"; - string expected_scrubbed = " " + Batch_terminator_replacement_string + " -- comment"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_semicolon_directly_after() - { - string sql_to_match = "jalla /;"; - string expected_scrubbed = "jalla " + Batch_terminator_replacement_string + ";"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - } - - public class should_not_replace_on - { - private ITestOutputHelper _testOutput; - private BatchSplitterReplacer Replacer; - - public should_not_replace_on(ITestOutputHelper testOutput) - { - _testOutput = testOutput; - Replacer = new BatchSplitterReplacer(new OracleSyntax()); - } - - [Fact] - public void slash_when_slash_is_the_last_part_of_the_last_word_on_a_line() - { - string sql_to_match = Words_to_check + @"/ -"; - string expected_scrubbed = Words_to_check + @"/ -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_double_dash_comment_starting_line() - { - string sql_to_match = @"--/ -"; - string expected_scrubbed = @"--/ -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_double_dash_comment_and_space_starting_line() - { - string sql_to_match = @"-- / -"; - string expected_scrubbed = @"-- / -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_double_dash_comment_and_space_starting_line_and_words_after_slash() - { - string sql_to_match = @"-- / " + Words_to_check + @" -"; - string expected_scrubbed = @"-- / " + Words_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_double_dash_comment_and_space_starting_line_and_symbols_after_slash() - { - string sql_to_match = @"-- / " + Symbols_to_check + @" -"; - string expected_scrubbed = @"-- / " + Symbols_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_double_dash_comment_and_tab_starting_line() - { - string sql_to_match = "--" + "\t" + @"/ -"; - string expected_scrubbed = @"--" + "\t" + @"/ -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_double_dash_comment_and_tab_starting_line_and_words_after_slash() - { - string sql_to_match = @"--" + "\t" + @"/ " + Words_to_check + @" -"; - string expected_scrubbed = @"--" + "\t" + @"/ " + Words_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_double_dash_comment_and_tab_starting_line_and_symbols_after_slash() - { - string sql_to_match = @"--" + "\t" + @"/ " + Symbols_to_check + @" -"; - string expected_scrubbed = @"--" + "\t" + @"/ " + Symbols_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_double_dash_comment_starting_line_with_words_before_slash() - { - string sql_to_match = @"-- " + Words_to_check + @" / -"; - string expected_scrubbed = @"-- " + Words_to_check + @" / -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_when_between_tick_marks() - { - const string sql_to_match = @"' / - '"; - const string expected_scrubbed = @"' / - '"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void - slash_when_between_tick_marks_with_symbols_and_words_before_ending_on_same_line() - { - string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" /'"; - string expected_scrubbed = - @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" /'"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_when_between_tick_marks_with_symbols_and_words_before() - { - string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" / - '"; - string expected_scrubbed = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" / - '"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_when_between_tick_marks_with_symbols_and_words_after() - { - string sql_to_match = @"' / - " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @"'"; - string expected_scrubbed = @"' / - " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @"'"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_with_double_dash_comment_starting_line_with_symbols_before_slash() - { - string sql_to_match = @"--" + Symbols_to_check + @" / -"; - string expected_scrubbed = @"--" + Symbols_to_check + @" / -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void - slash_with_double_dash_comment_starting_line_with_words_and_symbols_before_slash() - { - string sql_to_match = @"--" + Symbols_to_check + Words_to_check + @" / -"; - string expected_scrubbed = @"--" + Symbols_to_check + Words_to_check + @" / -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_inside_of_comments() - { - string sql_to_match = @"/* / */"; - string expected_scrubbed = @"/* / */"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_inside_of_comments_with_a_line_break() - { - string sql_to_match = @"/* / -*/"; - string expected_scrubbed = @"/* / -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_inside_of_comments_with_words_before() - { - string sql_to_match = - @"/* -" + Words_to_check + @" / - -*/"; - string expected_scrubbed = - @"/* -" + Words_to_check + @" / - -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_inside_of_comments_with_words_before_on_a_different_line() - { - string sql_to_match = - @"/* -" + Words_to_check + @" -/ - -*/"; - string expected_scrubbed = - @"/* -" + Words_to_check + @" -/ - -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_inside_of_comments_with_words_before_and_after_on_different_lines() - { - string sql_to_match = - @"/* -" + Words_to_check + @" -/ - -" + Words_to_check + @" -*/"; - string expected_scrubbed = - @"/* -" + Words_to_check + @" -/ - -" + Words_to_check + @" -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void slash_inside_of_comments_with_symbols_after_on_different_lines() - { - string sql_to_match = - @"/* -/ - -" + Symbols_to_check + @" -*/"; - string expected_scrubbed = - @"/* -/ - -" + Symbols_to_check + @" -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - } - -} diff --git a/unittests/Oracle/Basic_tests/OracleStatementSplitter_.cs b/unittests/Oracle/Basic_tests/OracleStatementSplitter_.cs new file mode 100644 index 00000000..c5534b7b --- /dev/null +++ b/unittests/Oracle/Basic_tests/OracleStatementSplitter_.cs @@ -0,0 +1,504 @@ +using grate.Infrastructure; +using grate.Oracle.Infrastructure; +using Oracle.TestInfrastructure; + +// ReSharper disable InconsistentNaming + +namespace Oracle.Basic_tests; + + +public class OracleStatementSplitter_ +{ + private const string Symbols_to_check = "`~!@#$%^&*()-_+=,.;:'\"[]\\/?<>"; + private const string Words_to_check = "abcdefghijklmnopqrstuvwzyz0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + // ReSharper disable once InconsistentNaming + public class should_replace_on + { + private ITestOutputHelper _testOutput; + private OracleStatementSplitter _splitter; + + public should_replace_on(ITestOutputHelper testOutput) + { + _testOutput = testOutput; + _splitter = new OracleStatementSplitter(); + } + + [Fact] + public void full_statement_without_issue() + { + string sql_to_match = OracleSplitterContext.FullSplitter.PLSqlStatement; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.NotEmpty(result); + Assert.True(result.Count > 1, "Should split into multiple statements"); + Assert.Equal(result, OracleSplitterContext.FullSplitter.PLSqlStatementScrubbed); + } + + [Fact] + public void slash_with_space() + { + const string sql_to_match = @" / "; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void slash_with_tab() + { + string sql_to_match = @" /" + "\t"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(["\t"],result); + } + + [Fact] + public void slash_by_itself() + { + const string sql_to_match = @"/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void slash_starting_file() + { + const string sql_to_match = @"/ +whatever"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_new_line() + { + const string sql_to_match = @" / +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Theory] + [InlineData("\n", "LF")] + public void slash_with_one_new_line_after_double_dash_comments_lf(string line_ending, string _) + { + string sql_to_match = $"--{line_ending}/{line_ending}"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(["--" + line_ending], result); + } + + [Theory] + [InlineData("\r\n", "CRLF")] + public void slash_with_one_new_line_after_double_dash_comments_crlf(string line_ending, string _) + { + string sql_to_match = $"--{line_ending}/{line_ending}"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(["--" + line_ending, line_ending], result); + } + + [Fact] + public void slash_with_one_new_line_after_double_dash_comments_and_words() + { + string sql_to_match = @"-- " + Words_to_check + @" +/ +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_new_line_after_double_dash_comments_and_symbols() + { + string sql_to_match = @"-- " + Symbols_to_check + @" +/ +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_on_its_own_line() + { + const string sql_to_match = @" +/ +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void slash_with_no_line_terminator() + { + const string sql_to_match = @" / "; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void slash_with_words_before() + { + string sql_to_match = Words_to_check + @" / +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_symbols_and_words_before() + { + string sql_to_match = Symbols_to_check + Words_to_check + @" / +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_words_and_symbols_before() + { + string sql_to_match = Words_to_check + Symbols_to_check + @" / +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_words_after_on_the_same_line() + { + string sql_to_match = @" / " + Words_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_words_after_on_the_same_line_including_symbols() + { + string sql_to_match = @" / " + Words_to_check + Symbols_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_words_before_and_after_on_the_same_line() + { + string sql_to_match = Words_to_check + @" / " + Words_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal([Words_to_check + " "," " + Words_to_check], result); + } + + [Fact] + public void slash_with_words_before_and_after_on_the_same_line_including_symbols() + { + string sql_to_match = Words_to_check + Symbols_to_check.Replace("'", "").Replace("\"", "") + + " / BOB" + Symbols_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal([ Words_to_check + Symbols_to_check.Replace("'", "").Replace("\"", "") + + " ", " BOB" + Symbols_to_check], result); + } + + [Fact] + public void slash_after_double_dash_comment_with_single_quote_and_single_quote_after_slash() + { + string sql_to_match = Words_to_check + @" -- ' +/ +select '' +/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal([Words_to_check + " -- '\n", "\nselect ''\n"], result); + } + + [Fact] + public void slash_with_comment_after() + { + string sql_to_match = " / -- comment"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_semicolon_directly_after() + { + string sql_to_match = "jalla /;"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(["jalla ", ";"], result); + } + + } + + public class should_not_replace_on + { + private ITestOutputHelper _testOutput; + private OracleStatementSplitter _splitter; + + public should_not_replace_on(ITestOutputHelper testOutput) + { + _testOutput = testOutput; + _splitter = new OracleStatementSplitter(); + } + + [Fact] + public void slash_when_slash_is_the_last_part_of_the_last_word_on_a_line() + { + string sql_to_match = Words_to_check + @"/ +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_double_dash_comment_starting_line() + { + string sql_to_match = @"--/ +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_double_dash_comment_and_space_starting_line() + { + string sql_to_match = @"-- / +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_double_dash_comment_and_space_starting_line_and_words_after_slash() + { + string sql_to_match = @"-- / " + Words_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_double_dash_comment_and_space_starting_line_and_symbols_after_slash() + { + string sql_to_match = @"-- / " + Symbols_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_double_dash_comment_and_tab_starting_line() + { + string sql_to_match = "--" + "\t" + @"/ +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_double_dash_comment_and_tab_starting_line_and_words_after_slash() + { + string sql_to_match = @"--" + "\t" + @"/ " + Words_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_double_dash_comment_and_tab_starting_line_and_symbols_after_slash() + { + string sql_to_match = @"--" + "\t" + @"/ " + Symbols_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_double_dash_comment_starting_line_with_words_before_slash() + { + string sql_to_match = @"-- " + Words_to_check + @" / +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_when_between_tick_marks() + { + const string sql_to_match = @"' / + '"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void + slash_when_between_tick_marks_with_symbols_and_words_before_ending_on_same_line() + { + string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" /'"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_when_between_tick_marks_with_symbols_and_words_before() + { + string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" / + '"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_when_between_tick_marks_with_symbols_and_words_after() + { + string sql_to_match = @"' / + " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @"'"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_with_double_dash_comment_starting_line_with_symbols_before_slash() + { + string sql_to_match = @"--" + Symbols_to_check + @" / +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void + slash_with_double_dash_comment_starting_line_with_words_and_symbols_before_slash() + { + string sql_to_match = @"--" + Symbols_to_check + Words_to_check + @" / +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_inside_of_comments() + { + string sql_to_match = @"/* / */"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_inside_of_comments_with_a_line_break() + { + string sql_to_match = @"/* / +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_inside_of_comments_with_words_before() + { + string sql_to_match = + @"/* +" + Words_to_check + @" / + +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_inside_of_comments_with_words_before_on_a_different_line() + { + string sql_to_match = + @"/* +" + Words_to_check + @" +/ + +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_inside_of_comments_with_words_before_and_after_on_different_lines() + { + string sql_to_match = + @"/* +" + Words_to_check + @" +/ + +" + Words_to_check + @" +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void slash_inside_of_comments_with_symbols_after_on_different_lines() + { + string sql_to_match = + @"/* +/ + +" + Symbols_to_check + @" +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + } + + public class Split + { + private readonly OracleStatementSplitter _splitter = new(); + + [Fact] + public void Splits_and_removes_GO_statements() + { + var original = @" +SELECT * FROM v$version WHERE banner LIKE 'Oracle%'; + + +/ +SELECT 1 +"; + var batches = _splitter.Split(original); + + Assert.Equal(2, batches.Count()); + } + } +} diff --git a/unittests/Oracle/Basic_tests/StatementSplitter_.cs b/unittests/Oracle/Basic_tests/StatementSplitter_.cs deleted file mode 100644 index 3beae1ef..00000000 --- a/unittests/Oracle/Basic_tests/StatementSplitter_.cs +++ /dev/null @@ -1,33 +0,0 @@ -using grate.Infrastructure; -using grate.Migration; -using grate.Oracle.Infrastructure; - -namespace Oracle.Basic_tests; - - -// ReSharper disable once InconsistentNaming -public class StatementSplitter_ -{ - private readonly StatementSplitter _splitter; - - public StatementSplitter_() - { - _splitter = new StatementSplitter(new OracleSyntax()); - } - - [Fact] - public void Splits_and_removes_GO_statements() - { - var original = @" -SELECT * FROM v$version WHERE banner LIKE 'Oracle%'; - - -/ -SELECT 1 -"; - var batches = _splitter.Split(original); - - Assert.Equal(2, batches.Count()); - } - -} diff --git a/unittests/Oracle/TestInfrastructure/OracleSplitterContext.cs b/unittests/Oracle/TestInfrastructure/OracleSplitterContext.cs index ac1fe7e3..c6adf78a 100644 --- a/unittests/Oracle/TestInfrastructure/OracleSplitterContext.cs +++ b/unittests/Oracle/TestInfrastructure/OracleSplitterContext.cs @@ -99,25 +99,25 @@ INSERT [dbo].[Foo] ([Bar]) VALUES (N'/ speed racer, / speed racer, / speed racer /"; - public static readonly string PLSqlStatementScrubbed = @" + public static readonly string[] PLSqlStatementScrubbed = [@" BOB1 -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" /* COMMENT */ BOB2 -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" -- / -BOB3 " + StatementSplitter.BatchTerminatorReplacementString + @" +BOB3 ", @" --`~!@#$%^&*()-_+=,.;:'""[]\/?<> / BOB5 - " + StatementSplitter.BatchTerminatorReplacementString + @" + ", @" BOB6 -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" /* / */ @@ -132,12 +132,12 @@ INSERT [dbo].[Foo] ([Bar]) VALUES (N'/ speed racer, / speed racer, / speed racer BOB8 -- -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" BOB9 -- `~!@#$%^&*()-_+=,.;:'""[]\/?<> -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" BOB10/ @@ -165,7 +165,7 @@ yeppsasd decimal(20, 6) NULL, slsald varchar(15) NULL, uhasdf varchar(15) NULL, daf_asdfasdf DECIMAL(20,6) NULL; -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Daily job', @step_id=1, @@ -182,40 +182,14 @@ dml statements / dml statements ' -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" INSERT [dbo].[Foo] ([Bar]) VALUES (N'hello--world. Thanks!') INSERT [dbo].[Foo] ([Bar]) VALUES (N'/ speed racer, / speed racer, / speed racer /!!!!! ') -" + StatementSplitter.BatchTerminatorReplacementString + @""; - - public static readonly string plsql_statement = - @" -SQL1; -; -SQL2; -; -tmpSql := 'DROP SEQUENCE mutatieStockID'; -EXECUTE IMMEDIATE tmpSql; -; -BEGIN -INSERT into Table (columnname) values ("";""); -UPDATE Table set columnname="";""; -END; -"; - public static readonly string plsql_statement_scrubbed = @" -SQL1; -" + StatementSplitter.BatchTerminatorReplacementString + @" -SQL2; -" + StatementSplitter.BatchTerminatorReplacementString + @" -tmpSql := 'DROP SEQUENCE mutatieStockID'; -EXECUTE IMMEDIATE tmpSql; -" + StatementSplitter.BatchTerminatorReplacementString + @" -BEGIN -INSERT into Table (columnname) values ("";""); -UPDATE Table set columnname="";""; -END; -"; +"]; + + } } diff --git a/unittests/PostgreSQL/Statement_Splitting/StatementSplitter_.cs b/unittests/PostgreSQL/Statement_Splitting/PostgreSqlStatementSplitter_.cs similarity index 92% rename from unittests/PostgreSQL/Statement_Splitting/StatementSplitter_.cs rename to unittests/PostgreSQL/Statement_Splitting/PostgreSqlStatementSplitter_.cs index 8b6b5439..c3f9ffdb 100644 --- a/unittests/PostgreSQL/Statement_Splitting/StatementSplitter_.cs +++ b/unittests/PostgreSQL/Statement_Splitting/PostgreSqlStatementSplitter_.cs @@ -1,18 +1,17 @@ using grate.Infrastructure; -using grate.Migration; using grate.PostgreSql.Infrastructure; namespace Basic_tests.Infrastructure.PostgreSQL.Statement_Splitting; // ReSharper disable once InconsistentNaming -public class StatementSplitter_ +public class PostgreSqlStatementSplitter_ { - private readonly StatementSplitter _statementSplitter; + private readonly PostgreSqlStatementSplitter _statementSplitter; - public StatementSplitter_() + public PostgreSqlStatementSplitter_() { - _statementSplitter = new StatementSplitter(new PostgreSqlSyntax()); + _statementSplitter = new PostgreSqlStatementSplitter(); } [Fact] diff --git a/unittests/SqlServer/Basic_tests/BatchSplitterReplacer_.cs b/unittests/SqlServer/Basic_tests/BatchSplitterReplacer_.cs deleted file mode 100644 index 61814679..00000000 --- a/unittests/SqlServer/Basic_tests/BatchSplitterReplacer_.cs +++ /dev/null @@ -1,598 +0,0 @@ -using grate.Infrastructure; -using grate.Migration; -using grate.SqlServer.Infrastructure; -using SqlServer.TestInfrastructure; - -// ReSharper disable InconsistentNaming - -namespace SqlServer.Basic_tests; - -public class BatchSplitterReplacer_ -{ - private const string Batch_terminator_replacement_string = StatementSplitter.BatchTerminatorReplacementString; - - private const string Symbols_to_check = "`~!@#$%^&*()-_+=,.;:'\"[]\\/?<>"; - private const string Words_to_check = "abcdefghijklmnopqrstuvwzyz0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - public class should_replace_on - { - private ITestOutputHelper _testOutput; - private BatchSplitterReplacer Replacer; - - public should_replace_on(ITestOutputHelper testOutput) - { - _testOutput = testOutput; - Replacer = new BatchSplitterReplacer(new SqlServerSyntax()); - } - - [Fact] - public void full_statement_without_issue() - { - string sql_to_match = SqlServerSplitterContext.FullSplitter.tsql_statement; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(SqlServerSplitterContext.FullSplitter.tsql_statement_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_space() - { - const string sql_to_match = @" GO "; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" "; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_tab() - { - string sql_to_match = @" GO" + "\t"; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + "\t"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_by_itself() - { - const string sql_to_match = @"GO"; - string expected_scrubbed = Batch_terminator_replacement_string; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_starting_file() - { - const string sql_to_match = @"GO -whatever"; - string expected_scrubbed = Batch_terminator_replacement_string + @" -whatever"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_new_line() - { - const string sql_to_match = @" GO -"; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_on_new_line_after_double_dash_comments() - { - const string sql_to_match = - @"-- -GO -"; - string expected_scrubbed = - @"-- -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_on_new_line_after_double_dash_comments_and_words() - { - string sql_to_match = @"-- " + Words_to_check + @" -GO -"; - string expected_scrubbed = @"-- " + Words_to_check + @" -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_new_line_after_double_dash_comments_and_symbols() - { - string sql_to_match = @"-- " + Symbols_to_check + @" -GO -"; - string expected_scrubbed = @"-- " + Symbols_to_check + @" -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_on_its_own_line() - { - const string sql_to_match = @" -GO -"; - string expected_scrubbed = @" -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_no_line_terminator() - { - const string sql_to_match = @" GO "; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" "; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_before() - { - string sql_to_match = Words_to_check + @" GO -"; - string expected_scrubbed = Words_to_check + @" " + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_symbols_and_words_before() - { - string sql_to_match = Symbols_to_check + Words_to_check + @" GO -"; - string expected_scrubbed = Symbols_to_check + Words_to_check + @" " + - Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_and_symbols_before() - { - string sql_to_match = Words_to_check + Symbols_to_check + @" GO -"; - string expected_scrubbed = Words_to_check + Symbols_to_check + @" " + - Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_after_on_the_same_line() - { - string sql_to_match = @" GO " + Words_to_check; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" " + Words_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_after_on_the_same_line_including_symbols() - { - string sql_to_match = @" GO " + Words_to_check + Symbols_to_check; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" " + Words_to_check + - Symbols_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_before_and_after_on_the_same_line() - { - string sql_to_match = Words_to_check + @" GO " + Words_to_check; - string expected_scrubbed = Words_to_check + @" " + Batch_terminator_replacement_string + @" " + - Words_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_before_and_after_on_the_same_line_including_symbols() - { - string sql_to_match = Words_to_check + Symbols_to_check.Replace("'", "").Replace("\"", "") + - " GO BOB" + Symbols_to_check; - string expected_scrubbed = Words_to_check + Symbols_to_check.Replace("'", "").Replace("\"", "") + - " " + Batch_terminator_replacement_string + " BOB" + Symbols_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_after_double_dash_comment_with_single_quote_and_single_quote_after_go() - { - string sql_to_match = Words_to_check + @" -- ' -GO -select '' -go"; - string expected_scrubbed = Words_to_check + @" -- ' -" + Batch_terminator_replacement_string + @" -select '' -" + Batch_terminator_replacement_string; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_comment_after() - { - string sql_to_match = " GO -- comment"; - string expected_scrubbed = " " + Batch_terminator_replacement_string + " -- comment"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_semicolon_directly_after() - { - string sql_to_match = "jalla GO;"; - string expected_scrubbed = "jalla " + Batch_terminator_replacement_string + ";"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - } - - public class should_not_replace_on - { - private readonly ITestOutputHelper _testOutput; - private readonly BatchSplitterReplacer _replacer; - - public should_not_replace_on(ITestOutputHelper testOutput) - { - _testOutput = testOutput; - _replacer = new BatchSplitterReplacer(new SqlServerSyntax()); - } - - [Fact] - public void g() - { - const string sql_to_match = @" G -"; - const string expected_scrubbed = @" G -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void o() - { - const string sql_to_match = @" O -"; - const string expected_scrubbed = @" O -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_when_go_is_the_last_part_of_the_last_word_on_a_line() - { - string sql_to_match = Words_to_check + @"GO -"; - string expected_scrubbed = Words_to_check + @"GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_starting_line() - { - string sql_to_match = @"--GO -"; - string expected_scrubbed = @"--GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_space_starting_line() - { - string sql_to_match = @"-- GO -"; - string expected_scrubbed = @"-- GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_space_starting_line_and_words_after_go() - { - string sql_to_match = @"-- GO " + Words_to_check + @" -"; - string expected_scrubbed = @"-- GO " + Words_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_space_starting_line_and_symbols_after_go() - { - string sql_to_match = @"-- GO " + Symbols_to_check + @" -"; - string expected_scrubbed = @"-- GO " + Symbols_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_tab_starting_line() - { - string sql_to_match = "--" + "\t" + @"GO -"; - string expected_scrubbed = @"--" + "\t" + @"GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_tab_starting_line_and_words_after_go() - { - string sql_to_match = @"--" + "\t" + @"GO " + Words_to_check + @" -"; - string expected_scrubbed = @"--" + "\t" + @"GO " + Words_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_tab_starting_line_and_symbols_after_go() - { - string sql_to_match = @"--" + "\t" + @"GO " + Symbols_to_check + @" -"; - string expected_scrubbed = @"--" + "\t" + @"GO " + Symbols_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_starting_line_with_words_before_go() - { - string sql_to_match = @"-- " + Words_to_check + @" GO -"; - string expected_scrubbed = @"-- " + Words_to_check + @" GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_when_between_tick_marks() - { - const string sql_to_match = @"' GO - '"; - const string expected_scrubbed = @"' GO - '"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void - go_when_between_tick_marks_with_symbols_and_words_before_ending_on_same_line() - { - string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO'"; - string expected_scrubbed = - @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO'"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_when_between_tick_marks_with_symbols_and_words_before() - { - string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO - '"; - string expected_scrubbed = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO - '"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_when_between_tick_marks_with_symbols_and_words_after() - { - string sql_to_match = @"' GO - " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @"'"; - string expected_scrubbed = @"' GO - " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @"'"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_starting_line_with_symbols_before_go() - { - string sql_to_match = @"--" + Symbols_to_check + @" GO -"; - string expected_scrubbed = @"--" + Symbols_to_check + @" GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void - go_with_double_dash_comment_starting_line_with_words_and_symbols_before_go() - { - string sql_to_match = @"--" + Symbols_to_check + Words_to_check + @" GO -"; - string expected_scrubbed = @"--" + Symbols_to_check + Words_to_check + @" GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments() - { - string sql_to_match = @"/* GO */"; - string expected_scrubbed = @"/* GO */"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments_with_a_line_break() - { - string sql_to_match = @"/* GO -*/"; - string expected_scrubbed = @"/* GO -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments_with_words_before() - { - string sql_to_match = - @"/* -" + Words_to_check + @" GO - -*/"; - string expected_scrubbed = - @"/* -" + Words_to_check + @" GO - -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments_with_words_before_on_a_different_line() - { - string sql_to_match = - @"/* -" + Words_to_check + @" -GO - -*/"; - string expected_scrubbed = - @"/* -" + Words_to_check + @" -GO - -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments_with_words_before_and_after_on_different_lines() - { - string sql_to_match = - @"/* -" + Words_to_check + @" -GO - -" + Words_to_check + @" -*/"; - string expected_scrubbed = - @"/* -" + Words_to_check + @" -GO - -" + Words_to_check + @" -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments_with_symbols_after_on_different_lines() - { - string sql_to_match = - @"/* -GO - -" + Symbols_to_check + @" -*/"; - string expected_scrubbed = - @"/* -GO - -" + Symbols_to_check + @" -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - } - -} diff --git a/unittests/SqlServer/Basic_tests/SqlServerStatementSplitter_.cs b/unittests/SqlServer/Basic_tests/SqlServerStatementSplitter_.cs new file mode 100644 index 00000000..606dab03 --- /dev/null +++ b/unittests/SqlServer/Basic_tests/SqlServerStatementSplitter_.cs @@ -0,0 +1,589 @@ +using grate.Infrastructure; +using grate.SqlServer.Infrastructure; +using SqlServer.TestInfrastructure; + +// ReSharper disable InconsistentNaming + +namespace SqlServer.Basic_tests; + +public class SqlServerStatementSplitter_ +{ + private const string Symbols_to_check = "`~!@#$%^&*()-_+=,.;:'\"[]\\/?<>"; + private const string Words_to_check = "abcdefghijklmnopqrstuvwzyz0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + public class should_replace_on + { + private ITestOutputHelper _testOutput; + private SqlServerStatementSplitter _splitter; + + public should_replace_on(ITestOutputHelper testOutput) + { + _testOutput = testOutput; + _splitter = new SqlServerStatementSplitter(); + } + + [Fact] + public void full_statement_without_issue() + { + string sql_to_match = SqlServerSplitterContext.FullSplitter.tsql_statement; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.NotEmpty(result); + Assert.True(result.Count > 1, "Should split into multiple statements"); + Assert.Equal(result, SqlServerSplitterContext.FullSplitter.tsql_statement_scrubbed); + } + + [Fact] + public void go_with_space() + { + const string sql_to_match = @" GO "; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void go_with_tab() + { + string sql_to_match = @" GO" + "\t"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void go_by_itself() + { + const string sql_to_match = @"GO"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void go_starting_file() + { + const string sql_to_match = @"GO +whatever"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains("whatever", result[0]); + } + + [Fact] + public void go_with_new_line() + { + const string sql_to_match = @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Theory] + [InlineData("\r\n", "CRLF")] + [InlineData("\n", "LF")] + public void go_with_on_new_line_after_double_dash_comments(string line_ending, string _) + { + string sql_to_match = $"--{line_ending}GO{line_ending}"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(["--" + line_ending], result); + } + + [Fact] + public void go_with_on_new_line_after_double_dash_comments_and_words() + { + string sql_to_match = @"-- " + Words_to_check + @" +GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void go_with_new_line_after_double_dash_comments_and_symbols() + { + string sql_to_match = @"-- " + Symbols_to_check + @" +GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void go_on_its_own_line() + { + const string sql_to_match = @" +GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void go_with_no_line_terminator() + { + const string sql_to_match = @" GO "; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void go_with_words_before() + { + string sql_to_match = Words_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(Words_to_check.Trim(), result[0].Trim()); + } + + [Fact] + public void go_with_symbols_and_words_before() + { + string sql_to_match = Symbols_to_check + Words_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void go_with_words_and_symbols_before() + { + string sql_to_match = Words_to_check + Symbols_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void go_with_words_after_on_the_same_line() + { + string sql_to_match = @" GO " + Words_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains(Words_to_check.Substring(0, 5), result[0]); + } + + [Fact] + public void go_with_words_after_on_the_same_line_including_symbols() + { + string sql_to_match = @" GO " + Words_to_check + Symbols_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void go_with_words_before_and_after_on_the_same_line() + { + string sql_to_match = Words_to_check + @" GO " + Words_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(2, result.Count); + Assert.Equal(Words_to_check.Trim(), result[0].Trim()); + Assert.Equal(Words_to_check.Trim(), result[1].Trim()); + } + + [Fact] + public void go_with_words_before_and_after_on_the_same_line_including_symbols() + { + string sql_to_match = Words_to_check + Symbols_to_check.Replace("'", "").Replace("\"", "") + + " GO BOB" + Symbols_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(2, result.Count); + } + + [Fact] + public void go_after_double_dash_comment_with_single_quote_and_single_quote_after_go() + { + string sql_to_match = Words_to_check + @" -- ' +GO +select '' +go"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(2, result.Count); + } + + [Fact] + public void lowercase_go_statement() + { + const string sql_to_match = "\r\nwhere DataName = 'AttributeKeyMap'\r\ngo "; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains("DataName", result[0]); + } + + [Fact] + public void go_after_line_comment_containing_an_apostrophe() + { + const string sql_to_match = @"select 1 -- ' +GO +'' +GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(2, result.Count); + } + + [Fact] + public void go_with_comment_after() + { + string sql_to_match = " GO -- comment"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal([" -- comment"], result); + } + + [Fact] + public void go_with_semicolon_directly_after() + { + string sql_to_match = "jalla GO;"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(["jalla ", ";" ], result); + } + + } + + public class should_not_replace_on + { + private readonly ITestOutputHelper _testOutput; + private readonly SqlServerStatementSplitter _splitter; + + public should_not_replace_on(ITestOutputHelper testOutput) + { + _testOutput = testOutput; + _splitter = new SqlServerStatementSplitter(); + } + + [Fact] + public void g() + { + const string sql_to_match = @" G +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains("G", result[0]); + } + + [Fact] + public void o() + { + const string sql_to_match = @" O +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains("O", result[0]); + } + + [Fact] + public void go_when_go_is_the_last_part_of_the_last_word_on_a_line() + { + string sql_to_match = Words_to_check + @"GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains(Words_to_check.Substring(0, 5), result[0]); + } + + [Fact] + public void go_with_double_dash_comment_starting_line() + { + string sql_to_match = @"--GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_space_starting_line() + { + string sql_to_match = @"-- GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_space_starting_line_and_words_after_go() + { + string sql_to_match = @"-- GO " + Words_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_space_starting_line_and_symbols_after_go() + { + string sql_to_match = @"-- GO " + Symbols_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_tab_starting_line() + { + string sql_to_match = "--" + "\t" + @"GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_tab_starting_line_and_words_after_go() + { + string sql_to_match = @"--" + "\t" + @"GO " + Words_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_tab_starting_line_and_symbols_after_go() + { + string sql_to_match = @"--" + "\t" + @"GO " + Symbols_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_starting_line_with_words_before_go() + { + string sql_to_match = @"-- " + Words_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_when_between_tick_marks() + { + const string sql_to_match = @"' GO + '"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_a_multiline_string_literal() + { + const string sql_to_match = @"select ' 1 -- +GO +'"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void + go_when_between_tick_marks_with_symbols_and_words_before_ending_on_same_line() + { + string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO'"; + string expected_scrubbed = + @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO'"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_when_between_tick_marks_with_symbols_and_words_before() + { + string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO + '"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_when_between_tick_marks_with_symbols_and_words_after() + { + string sql_to_match = @"' GO + " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @"'"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_starting_line_with_symbols_before_go() + { + string sql_to_match = @"--" + Symbols_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void + go_with_double_dash_comment_starting_line_with_words_and_symbols_before_go() + { + string sql_to_match = @"--" + Symbols_to_check + Words_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments() + { + string sql_to_match = @"/* GO */"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments_with_a_line_break() + { + string sql_to_match = @"/* GO +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_nested_comments_with_a_line_break() + { + const string sql_to_match = @"/* /* */ GO +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments_with_words_before() + { + string sql_to_match = + @"/* +" + Words_to_check + @" GO + +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments_with_words_before_on_a_different_line() + { + string sql_to_match = + @"/* +" + Words_to_check + @" +GO + +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments_with_words_before_and_after_on_different_lines() + { + string sql_to_match = + @"/* +" + Words_to_check + @" +GO + +" + Words_to_check + @" +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments_with_symbols_after_on_different_lines() + { + string sql_to_match = + @"/* +GO + +" + Symbols_to_check + @" +*/"; + + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + } + + public class Split + { + private readonly SqlServerStatementSplitter _splitter = new(); + + [Fact] + public void Splits_and_removes_GO_statements() + { + var original = @" +SELECT @@VERSION; + + +GO +SELECT 1 +"; + var batches = _splitter.Split(original); + + Assert.Equal(2, batches.Count()); + } + } +} diff --git a/unittests/SqlServer/Basic_tests/StatementSplitter_.cs b/unittests/SqlServer/Basic_tests/StatementSplitter_.cs deleted file mode 100644 index 12bbedb7..00000000 --- a/unittests/SqlServer/Basic_tests/StatementSplitter_.cs +++ /dev/null @@ -1,33 +0,0 @@ -using grate.Infrastructure; -using grate.Migration; -using grate.SqlServer.Infrastructure; - -namespace SqlServer.Statement_Splitting; - - -// ReSharper disable once InconsistentNaming -public class StatementSplitter_ -{ - private readonly StatementSplitter _splitter; - - public StatementSplitter_() - { - _splitter = new StatementSplitter(new SqlServerSyntax()); - } - - [Fact] - public void Splits_and_removes_GO_statements() - { - var original = @" -SELECT @@VERSION; - - -GO -SELECT 1 -"; - var batches = _splitter.Split(original); - - Assert.Equal(2, batches.Count()); - } - -} diff --git a/unittests/SqlServer/TestInfrastructure/SqlServerSplitterContext.cs b/unittests/SqlServer/TestInfrastructure/SqlServerSplitterContext.cs index b175d4f3..df733f71 100644 --- a/unittests/SqlServer/TestInfrastructure/SqlServerSplitterContext.cs +++ b/unittests/SqlServer/TestInfrastructure/SqlServerSplitterContext.cs @@ -100,25 +100,25 @@ INSERT [dbo].[Foo] ([Bar]) VALUES (N'Go speed racer, go speed racer, go speed ra GO"; - public static readonly string tsql_statement_scrubbed = @" + public static readonly string[] tsql_statement_scrubbed = [@" BOB1 -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" /* COMMENT */ BOB2 -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" -- GO -BOB3 " + StatementSplitter.BatchTerminatorReplacementString + @" +BOB3 ", @" --`~!@#$%^&*()-_+=,.;:'""[]\/?<> GO BOB5 - " + StatementSplitter.BatchTerminatorReplacementString + @" + ", @" BOB6 -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" /* GO */ @@ -133,12 +133,12 @@ INSERT [dbo].[Foo] ([Bar]) VALUES (N'Go speed racer, go speed racer, go speed ra BOB8 -- -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" BOB9 -- `~!@#$%^&*()-_+=,.;:'""[]\/?<> -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" BOB10GO @@ -166,7 +166,7 @@ yeppsasd decimal(20, 6) NULL, slsald varchar(15) NULL, uhasdf varchar(15) NULL, daf_asdfasdf DECIMAL(20,6) NULL; -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Daily job', @step_id=1, @@ -183,40 +183,13 @@ dml statements GO dml statements ' -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" INSERT [dbo].[Foo] ([Bar]) VALUES (N'hello--world. Thanks!') INSERT [dbo].[Foo] ([Bar]) VALUES (N'Go speed racer, go speed racer, go speed racer go!!!!! ') -" + StatementSplitter.BatchTerminatorReplacementString + @""; - - public static readonly string plsql_statement = - @" -SQL1; -; -SQL2; -; -tmpSql := 'DROP SEQUENCE mutatieStockID'; -EXECUTE IMMEDIATE tmpSql; -; -BEGIN -INSERT into Table (columnname) values ("";""); -UPDATE Table set columnname="";""; -END; -"; - public static readonly string plsql_statement_scrubbed = @" -SQL1; -" + StatementSplitter.BatchTerminatorReplacementString + @" -SQL2; -" + StatementSplitter.BatchTerminatorReplacementString + @" -tmpSql := 'DROP SEQUENCE mutatieStockID'; -EXECUTE IMMEDIATE tmpSql; -" + StatementSplitter.BatchTerminatorReplacementString + @" -BEGIN -INSERT into Table (columnname) values ("";""); -UPDATE Table set columnname="";""; -END; -"; +"]; + } } diff --git a/unittests/SqlServerCaseSensitive/Basic_tests/BatchSplitterReplacer_.cs b/unittests/SqlServerCaseSensitive/Basic_tests/BatchSplitterReplacer_.cs deleted file mode 100644 index 83773904..00000000 --- a/unittests/SqlServerCaseSensitive/Basic_tests/BatchSplitterReplacer_.cs +++ /dev/null @@ -1,597 +0,0 @@ -using grate.Infrastructure; -using grate.SqlServer.Infrastructure; -using SqlServerCaseSensitive.TestInfrastructure; - -// ReSharper disable InconsistentNaming - -namespace SqlServerCaseSensitive.Basic_tests; - -public class BatchSplitterReplacer_ -{ - private const string Batch_terminator_replacement_string = StatementSplitter.BatchTerminatorReplacementString; - - private const string Symbols_to_check = "`~!@#$%^&*()-_+=,.;:'\"[]\\/?<>"; - private const string Words_to_check = "abcdefghijklmnopqrstuvwzyz0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - public class should_replace_on - { - private ITestOutputHelper _testOutput; - private BatchSplitterReplacer Replacer; - - public should_replace_on(ITestOutputHelper testOutput) - { - _testOutput = testOutput; - Replacer = new BatchSplitterReplacer(new SqlServerSyntax()); - } - - [Fact] - public void full_statement_without_issue() - { - string sql_to_match = SqlServerSplitterContext.FullSplitter.tsql_statement; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(SqlServerSplitterContext.FullSplitter.tsql_statement_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_space() - { - const string sql_to_match = @" GO "; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" "; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_tab() - { - string sql_to_match = @" GO" + "\t"; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + "\t"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_by_itself() - { - const string sql_to_match = @"GO"; - string expected_scrubbed = Batch_terminator_replacement_string; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_starting_file() - { - const string sql_to_match = @"GO -whatever"; - string expected_scrubbed = Batch_terminator_replacement_string + @" -whatever"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_new_line() - { - const string sql_to_match = @" GO -"; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_on_new_line_after_double_dash_comments() - { - const string sql_to_match = - @"-- -GO -"; - string expected_scrubbed = - @"-- -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_on_new_line_after_double_dash_comments_and_words() - { - string sql_to_match = @"-- " + Words_to_check + @" -GO -"; - string expected_scrubbed = @"-- " + Words_to_check + @" -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_new_line_after_double_dash_comments_and_symbols() - { - string sql_to_match = @"-- " + Symbols_to_check + @" -GO -"; - string expected_scrubbed = @"-- " + Symbols_to_check + @" -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_on_its_own_line() - { - const string sql_to_match = @" -GO -"; - string expected_scrubbed = @" -" + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_no_line_terminator() - { - const string sql_to_match = @" GO "; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" "; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_before() - { - string sql_to_match = Words_to_check + @" GO -"; - string expected_scrubbed = Words_to_check + @" " + Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_symbols_and_words_before() - { - string sql_to_match = Symbols_to_check + Words_to_check + @" GO -"; - string expected_scrubbed = Symbols_to_check + Words_to_check + @" " + - Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_and_symbols_before() - { - string sql_to_match = Words_to_check + Symbols_to_check + @" GO -"; - string expected_scrubbed = Words_to_check + Symbols_to_check + @" " + - Batch_terminator_replacement_string + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_after_on_the_same_line() - { - string sql_to_match = @" GO " + Words_to_check; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" " + Words_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_after_on_the_same_line_including_symbols() - { - string sql_to_match = @" GO " + Words_to_check + Symbols_to_check; - string expected_scrubbed = @" " + Batch_terminator_replacement_string + @" " + Words_to_check + - Symbols_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_before_and_after_on_the_same_line() - { - string sql_to_match = Words_to_check + @" GO " + Words_to_check; - string expected_scrubbed = Words_to_check + @" " + Batch_terminator_replacement_string + @" " + - Words_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_words_before_and_after_on_the_same_line_including_symbols() - { - string sql_to_match = Words_to_check + Symbols_to_check.Replace("'", "").Replace("\"", "") + - " GO BOB" + Symbols_to_check; - string expected_scrubbed = Words_to_check + Symbols_to_check.Replace("'", "").Replace("\"", "") + - " " + Batch_terminator_replacement_string + " BOB" + Symbols_to_check; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_after_double_dash_comment_with_single_quote_and_single_quote_after_go() - { - string sql_to_match = Words_to_check + @" -- ' -GO -select '' -go"; - string expected_scrubbed = Words_to_check + @" -- ' -" + Batch_terminator_replacement_string + @" -select '' -" + Batch_terminator_replacement_string; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_comment_after() - { - string sql_to_match = " GO -- comment"; - string expected_scrubbed = " " + Batch_terminator_replacement_string + " -- comment"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_semicolon_directly_after() - { - string sql_to_match = "jalla GO;"; - string expected_scrubbed = "jalla " + Batch_terminator_replacement_string + ";"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = Replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - } - - public class should_not_replace_on - { - private readonly ITestOutputHelper _testOutput; - private readonly BatchSplitterReplacer _replacer; - - public should_not_replace_on(ITestOutputHelper testOutput) - { - _testOutput = testOutput; - _replacer = new BatchSplitterReplacer(new SqlServerSyntax()); - } - - [Fact] - public void g() - { - const string sql_to_match = @" G -"; - const string expected_scrubbed = @" G -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void o() - { - const string sql_to_match = @" O -"; - const string expected_scrubbed = @" O -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_when_go_is_the_last_part_of_the_last_word_on_a_line() - { - string sql_to_match = Words_to_check + @"GO -"; - string expected_scrubbed = Words_to_check + @"GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_starting_line() - { - string sql_to_match = @"--GO -"; - string expected_scrubbed = @"--GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_space_starting_line() - { - string sql_to_match = @"-- GO -"; - string expected_scrubbed = @"-- GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_space_starting_line_and_words_after_go() - { - string sql_to_match = @"-- GO " + Words_to_check + @" -"; - string expected_scrubbed = @"-- GO " + Words_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_space_starting_line_and_symbols_after_go() - { - string sql_to_match = @"-- GO " + Symbols_to_check + @" -"; - string expected_scrubbed = @"-- GO " + Symbols_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_tab_starting_line() - { - string sql_to_match = "--" + "\t" + @"GO -"; - string expected_scrubbed = @"--" + "\t" + @"GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_tab_starting_line_and_words_after_go() - { - string sql_to_match = @"--" + "\t" + @"GO " + Words_to_check + @" -"; - string expected_scrubbed = @"--" + "\t" + @"GO " + Words_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_and_tab_starting_line_and_symbols_after_go() - { - string sql_to_match = @"--" + "\t" + @"GO " + Symbols_to_check + @" -"; - string expected_scrubbed = @"--" + "\t" + @"GO " + Symbols_to_check + @" -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_starting_line_with_words_before_go() - { - string sql_to_match = @"-- " + Words_to_check + @" GO -"; - string expected_scrubbed = @"-- " + Words_to_check + @" GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_when_between_tick_marks() - { - const string sql_to_match = @"' GO - '"; - const string expected_scrubbed = @"' GO - '"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void - go_when_between_tick_marks_with_symbols_and_words_before_ending_on_same_line() - { - string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO'"; - string expected_scrubbed = - @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO'"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_when_between_tick_marks_with_symbols_and_words_before() - { - string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO - '"; - string expected_scrubbed = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO - '"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_when_between_tick_marks_with_symbols_and_words_after() - { - string sql_to_match = @"' GO - " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @"'"; - string expected_scrubbed = @"' GO - " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @"'"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_with_double_dash_comment_starting_line_with_symbols_before_go() - { - string sql_to_match = @"--" + Symbols_to_check + @" GO -"; - string expected_scrubbed = @"--" + Symbols_to_check + @" GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void - go_with_double_dash_comment_starting_line_with_words_and_symbols_before_go() - { - string sql_to_match = @"--" + Symbols_to_check + Words_to_check + @" GO -"; - string expected_scrubbed = @"--" + Symbols_to_check + Words_to_check + @" GO -"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments() - { - string sql_to_match = @"/* GO */"; - string expected_scrubbed = @"/* GO */"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments_with_a_line_break() - { - string sql_to_match = @"/* GO -*/"; - string expected_scrubbed = @"/* GO -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments_with_words_before() - { - string sql_to_match = - @"/* -" + Words_to_check + @" GO - -*/"; - string expected_scrubbed = - @"/* -" + Words_to_check + @" GO - -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments_with_words_before_on_a_different_line() - { - string sql_to_match = - @"/* -" + Words_to_check + @" -GO - -*/"; - string expected_scrubbed = - @"/* -" + Words_to_check + @" -GO - -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments_with_words_before_and_after_on_different_lines() - { - string sql_to_match = - @"/* -" + Words_to_check + @" -GO - -" + Words_to_check + @" -*/"; - string expected_scrubbed = - @"/* -" + Words_to_check + @" -GO - -" + Words_to_check + @" -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - - [Fact] - public void go_inside_of_comments_with_symbols_after_on_different_lines() - { - string sql_to_match = - @"/* -GO - -" + Symbols_to_check + @" -*/"; - string expected_scrubbed = - @"/* -GO - -" + Symbols_to_check + @" -*/"; - _testOutput.WriteLine(sql_to_match); - string sql_statement_scrubbed = _replacer.Replace(sql_to_match); - Assert.Equal(expected_scrubbed, sql_statement_scrubbed); - } - } - -} diff --git a/unittests/SqlServerCaseSensitive/Basic_tests/SqlServerStatementSplitter_.cs b/unittests/SqlServerCaseSensitive/Basic_tests/SqlServerStatementSplitter_.cs new file mode 100644 index 00000000..ae7c6a61 --- /dev/null +++ b/unittests/SqlServerCaseSensitive/Basic_tests/SqlServerStatementSplitter_.cs @@ -0,0 +1,539 @@ +using grate.Infrastructure; +using grate.SqlServer.Infrastructure; +using SqlServerCaseSensitive.TestInfrastructure; + +// ReSharper disable InconsistentNaming + +namespace SqlServerCaseSensitive.Basic_tests; + +public class SqlServerStatementSplitter_ +{ + private const string Symbols_to_check = "`~!@#$%^&*()-_+=,.;:'\"[]\\/?<>"; + private const string Words_to_check = "abcdefghijklmnopqrstuvwzyz0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + public class should_replace_on + { + private ITestOutputHelper _testOutput; + private SqlServerStatementSplitter _splitter; + + public should_replace_on(ITestOutputHelper testOutput) + { + _testOutput = testOutput; + _splitter = new SqlServerStatementSplitter(); + } + + [Fact] + public void full_statement_without_issue() + { + string sql_to_match = SqlServerSplitterContext.FullSplitter.tsql_statement; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.NotEmpty(result); + Assert.True(result.Count > 1, "Should split into multiple statements"); + Assert.Equal(result, SqlServerSplitterContext.FullSplitter.tsql_statement_scrubbed); + } + + [Fact] + public void go_with_space() + { + const string sql_to_match = @" GO "; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void go_with_tab() + { + string sql_to_match = @" GO" + "\t"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void go_by_itself() + { + const string sql_to_match = @"GO"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void go_starting_file() + { + const string sql_to_match = @"GO +whatever"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains("whatever", result[0]); + } + + [Fact] + public void go_with_new_line() + { + const string sql_to_match = @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + + [Theory] + [InlineData("\r\n", "CRLF")] + [InlineData("\n", "LF")] + public void go_with_on_new_line_after_double_dash_comments(string line_ending, string _) + { + string sql_to_match = $"--{line_ending}GO{line_ending}"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(["--" + line_ending], result); + } + + [Fact] + public void go_with_on_new_line_after_double_dash_comments_and_words() + { + string sql_to_match = @"-- " + Words_to_check + @" +GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void go_with_new_line_after_double_dash_comments_and_symbols() + { + string sql_to_match = @"-- " + Symbols_to_check + @" +GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void go_on_its_own_line() + { + const string sql_to_match = @" +GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void go_with_no_line_terminator() + { + const string sql_to_match = @" GO "; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Empty(result); + } + + [Fact] + public void go_with_words_before() + { + string sql_to_match = Words_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(Words_to_check.Trim(), result[0].Trim()); + } + + [Fact] + public void go_with_symbols_and_words_before() + { + string sql_to_match = Symbols_to_check + Words_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void go_with_words_and_symbols_before() + { + string sql_to_match = Words_to_check + Symbols_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void go_with_words_after_on_the_same_line() + { + string sql_to_match = @" GO " + Words_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains(Words_to_check.Substring(0, 5), result[0]); + } + + [Fact] + public void go_with_words_after_on_the_same_line_including_symbols() + { + string sql_to_match = @" GO " + Words_to_check + Symbols_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + } + + [Fact] + public void go_with_words_before_and_after_on_the_same_line() + { + string sql_to_match = Words_to_check + @" GO " + Words_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal([Words_to_check + " ", " " + Words_to_check], result); + } + + [Fact] + public void go_with_words_before_and_after_on_the_same_line_including_symbols() + { + string sql_to_match = Words_to_check + Symbols_to_check.Replace("'", "").Replace("\"", "") + + " GO BOB" + Symbols_to_check; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(2, result.Count); + } + + [Fact] + public void go_after_double_dash_comment_with_single_quote_and_single_quote_after_go() + { + string sql_to_match = Words_to_check + @" -- ' +GO +select '' +go"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(2, result.Count); + } + + [Fact] + public void go_with_comment_after() + { + string sql_to_match = " GO -- comment"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal([" -- comment"], result); + } + + [Fact] + public void go_with_semicolon_directly_after() + { + string sql_to_match = "jalla GO;"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Equal(["jalla ", ";" ], result); + } + + } + + public class should_not_replace_on + { + private readonly ITestOutputHelper _testOutput; + private readonly SqlServerStatementSplitter _splitter; + + public should_not_replace_on(ITestOutputHelper testOutput) + { + _testOutput = testOutput; + _splitter = new SqlServerStatementSplitter(); + } + + [Fact] + public void g() + { + const string sql_to_match = @" G +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains("G", result[0]); + } + + [Fact] + public void o() + { + const string sql_to_match = @" O +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains("O", result[0]); + } + + [Fact] + public void go_when_go_is_the_last_part_of_the_last_word_on_a_line() + { + string sql_to_match = Words_to_check + @"GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Contains(Words_to_check.Substring(0, 5), result[0]); + } + + [Fact] + public void go_with_double_dash_comment_starting_line() + { + string sql_to_match = @"--GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_space_starting_line() + { + string sql_to_match = @"-- GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_space_starting_line_and_words_after_go() + { + string sql_to_match = @"-- GO " + Words_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_space_starting_line_and_symbols_after_go() + { + string sql_to_match = @"-- GO " + Symbols_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_tab_starting_line() + { + string sql_to_match = "--" + "\t" + @"GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_tab_starting_line_and_words_after_go() + { + string sql_to_match = @"--" + "\t" + @"GO " + Words_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_and_tab_starting_line_and_symbols_after_go() + { + string sql_to_match = @"--" + "\t" + @"GO " + Symbols_to_check + @" +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_starting_line_with_words_before_go() + { + string sql_to_match = @"-- " + Words_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_when_between_tick_marks() + { + const string sql_to_match = @"' GO + '"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void + go_when_between_tick_marks_with_symbols_and_words_before_ending_on_same_line() + { + string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO'"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_when_between_tick_marks_with_symbols_and_words_before() + { + string sql_to_match = @"' " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @" GO + '"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_when_between_tick_marks_with_symbols_and_words_after() + { + string sql_to_match = @"' GO + " + Symbols_to_check.Replace("'", string.Empty) + Words_to_check + @"'"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_with_double_dash_comment_starting_line_with_symbols_before_go() + { + string sql_to_match = @"--" + Symbols_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void + go_with_double_dash_comment_starting_line_with_words_and_symbols_before_go() + { + string sql_to_match = @"--" + Symbols_to_check + Words_to_check + @" GO +"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments() + { + string sql_to_match = @"/* GO */"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments_with_a_line_break() + { + string sql_to_match = @"/* GO +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments_with_words_before() + { + string sql_to_match = + @"/* +" + Words_to_check + @" GO + +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments_with_words_before_on_a_different_line() + { + string sql_to_match = + @"/* +" + Words_to_check + @" +GO + +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments_with_words_before_and_after_on_different_lines() + { + string sql_to_match = + @"/* +" + Words_to_check + @" +GO + +" + Words_to_check + @" +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + + [Fact] + public void go_inside_of_comments_with_symbols_after_on_different_lines() + { + string sql_to_match = + @"/* +GO + +" + Symbols_to_check + @" +*/"; + _testOutput.WriteLine(sql_to_match); + var result = _splitter.Split(sql_to_match).ToList(); + Assert.Single(result); + Assert.Equal(sql_to_match, result.Single()); + } + } + + public class Split + { + private readonly SqlServerStatementSplitter _splitter = new(); + + [Fact] + public void Splits_and_removes_GO_statements() + { + var original = @" +SELECT @@VERSION; + + +GO +SELECT 1 +"; + var batches = _splitter.Split(original); + + Assert.Equal(2, batches.Count()); + } + } +} diff --git a/unittests/SqlServerCaseSensitive/Basic_tests/StatementSplitter_.cs b/unittests/SqlServerCaseSensitive/Basic_tests/StatementSplitter_.cs deleted file mode 100644 index 14cbcf84..00000000 --- a/unittests/SqlServerCaseSensitive/Basic_tests/StatementSplitter_.cs +++ /dev/null @@ -1,32 +0,0 @@ -using grate.Infrastructure; -using grate.SqlServer.Infrastructure; - -namespace SqlServerCaseSensitive.Basic_tests; - - -// ReSharper disable once InconsistentNaming -public class StatementSplitter_ -{ - private readonly StatementSplitter _splitter; - - public StatementSplitter_() - { - _splitter = new StatementSplitter(new SqlServerSyntax()); - } - - [Fact] - public void Splits_and_removes_GO_statements() - { - var original = @" -SELECT @@VERSION; - - -GO -SELECT 1 -"; - var batches = _splitter.Split(original); - - Assert.Equal(2, batches.Count()); - } - -} diff --git a/unittests/SqlServerCaseSensitive/TestInfrastructure/SqlServerSplitterContext.cs b/unittests/SqlServerCaseSensitive/TestInfrastructure/SqlServerSplitterContext.cs index 84843edd..18b89a30 100644 --- a/unittests/SqlServerCaseSensitive/TestInfrastructure/SqlServerSplitterContext.cs +++ b/unittests/SqlServerCaseSensitive/TestInfrastructure/SqlServerSplitterContext.cs @@ -100,25 +100,25 @@ INSERT [dbo].[Foo] ([Bar]) VALUES (N'Go speed racer, go speed racer, go speed ra GO"; - public static readonly string tsql_statement_scrubbed = @" + public static readonly string[] tsql_statement_scrubbed =[ @" BOB1 -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" /* COMMENT */ BOB2 -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" -- GO -BOB3 " + StatementSplitter.BatchTerminatorReplacementString + @" +BOB3 ", @" --`~!@#$%^&*()-_+=,.;:'""[]\/?<> GO BOB5 - " + StatementSplitter.BatchTerminatorReplacementString + @" + ", @" BOB6 -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" /* GO */ @@ -133,12 +133,12 @@ INSERT [dbo].[Foo] ([Bar]) VALUES (N'Go speed racer, go speed racer, go speed ra BOB8 -- -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" BOB9 -- `~!@#$%^&*()-_+=,.;:'""[]\/?<> -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" BOB10GO @@ -166,7 +166,7 @@ yeppsasd decimal(20, 6) NULL, slsald varchar(15) NULL, uhasdf varchar(15) NULL, daf_asdfasdf DECIMAL(20,6) NULL; -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Daily job', @step_id=1, @@ -183,40 +183,13 @@ dml statements GO dml statements ' -" + StatementSplitter.BatchTerminatorReplacementString + @" +", @" INSERT [dbo].[Foo] ([Bar]) VALUES (N'hello--world. Thanks!') INSERT [dbo].[Foo] ([Bar]) VALUES (N'Go speed racer, go speed racer, go speed racer go!!!!! ') -" + StatementSplitter.BatchTerminatorReplacementString + @""; - - public static readonly string plsql_statement = - @" -SQL1; -; -SQL2; -; -tmpSql := 'DROP SEQUENCE mutatieStockID'; -EXECUTE IMMEDIATE tmpSql; -; -BEGIN -INSERT into Table (columnname) values ("";""); -UPDATE Table set columnname="";""; -END; -"; - public static readonly string plsql_statement_scrubbed = @" -SQL1; -" + StatementSplitter.BatchTerminatorReplacementString + @" -SQL2; -" + StatementSplitter.BatchTerminatorReplacementString + @" -tmpSql := 'DROP SEQUENCE mutatieStockID'; -EXECUTE IMMEDIATE tmpSql; -" + StatementSplitter.BatchTerminatorReplacementString + @" -BEGIN -INSERT into Table (columnname) values ("";""); -UPDATE Table set columnname="";""; -END; -"; +"]; + } }