From 648d7dbd3c5c85030deac3b3caca878fb16525bd Mon Sep 17 00:00:00 2001 From: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com> Date: Tue, 18 Apr 2023 20:57:13 -0700 Subject: [PATCH] Address warnings and (some) nullables (#2013) --- .../DataSource/Kusto/KustoDataSource.cs | 28 +-- .../DataSource/KustoQueryUtils.cs | 30 +-- .../DataSource/Monitor/MonitorDataSource.cs | 7 +- .../LanguageServices/BindingQueue.cs | 4 +- .../LanguageServices/LanguageService.cs | 10 +- .../Microsoft.Kusto.ServiceLayer.csproj | 4 +- .../QueryExecution/ResultSet.cs | 18 +- .../Scripting/ScriptingExtensionMethods.cs | 2 +- .../Utility/ResolvedFile.cs | 8 +- .../SqlScriptFormatters/FromSqlScript.cs | 15 +- .../Workspace/Contracts/ScriptFile.cs | 2 +- .../Workspace/Workspace.cs | 13 +- .../Microsoft.SqlTools.Credentials.csproj | 86 ++++---- .../BatchParser/BatchParserWrapper.cs | 4 +- ...crosoft.SqlTools.ManagedBatchParser.csproj | 2 +- .../ReliableConnection/AmbientSettings.cs | 2 +- .../ReliableConnection/CachedServerInfo.cs | 2 +- .../ReliableConnection/RetryPolicy.cs | 2 +- ...lTools.ResourceProvider.DefaultImpl.csproj | 2 +- ...Microsoft.SqlTools.ResourceProvider.csproj | 6 +- .../Program.cs | 2 +- .../Admin/Database/AzureSqlDbHelper.cs | 12 +- .../Agent/AgentService.cs | 8 +- .../Agent/Jobs/JobStepSubSystems.cs | 36 +-- .../Agent/Jobs/JobStepsActions.cs | 2 +- .../Agent/Jobs/ScheduleData.cs | 43 ++-- .../AzureFunctions/AzureFunctionsUtils.cs | 2 +- .../Connection/ConnectionService.cs | 6 +- .../DacFx/GetObjectsFromTSqlModelOperation.cs | 2 +- .../RestoreOperation/RestoreOptionFactory.cs | 208 +++++++++--------- .../EditData/UpdateManagement/CellUpdate.cs | 9 +- .../ShowPlan/DataReaderNodeBuilder.cs | 21 +- .../LanguageServices/BindingQueue.cs | 3 +- .../Completion/SqlCompletionItem.cs | 9 +- .../LanguageServices/LanguageService.cs | 4 +- .../Management/Common/DataContainer.cs | 4 +- .../Microsoft.SqlTools.ServiceLayer.csproj | 4 +- .../Profiler/ProfilerSession.cs | 4 +- .../SaveAsMarkdownFileStreamWriter.cs | 10 +- .../QueryExecution/ResultSet.cs | 18 +- .../SchemaCompare/SchemaCompareUtils.cs | 13 +- .../Scripting/ScripterCore.cs | 12 +- .../Scripting/ScriptingExtensionMethods.cs | 2 +- .../TableDesigner/EnumUtils.cs | 4 +- .../Utility/ResolvedFile.cs | 2 +- .../SqlScriptFormatters/FromSqlScript.cs | 17 +- .../Workspace/Contracts/ScriptFile.cs | 2 +- .../Workspace/Workspace.cs | 13 +- .../AzureFunctionsServiceTests.cs | 2 +- .../Connection/ReliableConnectionTests.cs | 12 +- .../DisasterRecovery/BackupRestoreUrlTests.cs | 2 +- .../RestoreDatabaseServiceTests.cs | 2 +- .../LanguageServer/LanguageServiceTests.cs | 4 +- ...Tools.ServiceLayer.IntegrationTests.csproj | 2 - .../ObjectExplorerServiceTests.cs | 24 +- .../SqlParameterizerTests.cs | 6 +- .../SharedAccessSignatureCreatorTests.cs | 2 +- .../EditData/CellUpdateTests.cs | 6 +- .../EditData/RowCreateTests.cs | 77 ++++--- .../EditData/RowEditBaseTests.cs | 2 +- .../EditData/RowUpdateTests.cs | 50 +++-- .../EditData/SessionTests.cs | 104 ++++----- .../LanguageServer/AutocompleteTests.cs | 2 +- .../LanguageServer/LanguageServiceTests.cs | 2 +- .../Messaging/MessageReaderTests.cs | 12 +- .../Messaging/TestMessageTypes.cs | 12 +- ...oft.SqlTools.ServiceLayer.UnitTests.csproj | 4 +- .../ObjectExplorer/GroupBySchemaTests.cs | 2 +- .../QueryExecution/Common.cs | 2 +- .../SaveAsCsvFileStreamWriterTests.cs | 21 +- .../SaveAsExcelFileStreamWriterHelperTests.cs | 24 +- .../SaveAsMarkdownFileStreamWriterTests.cs | 7 +- ...erviceBufferFileStreamReaderWriterTests.cs | 71 +++--- .../QueryExecution/Execution/BatchTests.cs | 12 +- .../Execution/DbColumnWrapperTests.cs | 2 +- .../QueryExecution/Execution/QueryTests.cs | 6 +- .../QueryExecution/ExecutionPlanTests.cs | 2 +- .../SaveResults/SerializationServiceTests.cs | 4 +- .../Azure/AzureAuthenticationManagerTest.cs | 4 +- .../Azure/AzureTestContext.cs | 2 +- .../FirewallRuleServiceTest.cs | 2 +- .../SqlProjects/SqlProjectTests.cs | 2 +- .../UtilityTests/ToSqlScriptTests.cs | 53 +++-- 83 files changed, 674 insertions(+), 588 deletions(-) diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Kusto/KustoDataSource.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Kusto/KustoDataSource.cs index 65e05c37..c49f2224 100644 --- a/src/Microsoft.Kusto.ServiceLayer/DataSource/Kusto/KustoDataSource.cs +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Kusto/KustoDataSource.cs @@ -413,22 +413,19 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Kusto { var returnList = new List(); - if (_folderMetadata.ContainsKey(key)) + if (_folderMetadata.TryGetValue(key, out IEnumerable? folderMetadata)) { - returnList.AddRange(_folderMetadata[key] - .OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase)); + returnList.AddRange(folderMetadata.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase)); } - if (_tableMetadata.ContainsKey(key)) + if (_tableMetadata.TryGetValue(key, out IEnumerable? tableMetadata)) { - returnList.AddRange(_tableMetadata[key] - .OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase)); + returnList.AddRange(tableMetadata.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase)); } - if (_functionMetadata.ContainsKey(key)) + if (_functionMetadata.TryGetValue(key, out IEnumerable? functionMetadata)) { - returnList.AddRange(_functionMetadata[key] - .OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase)); + returnList.AddRange(functionMetadata.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase)); } return returnList; @@ -515,16 +512,15 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Kusto private IEnumerable GetTableSchema(TableMetadata tableMetadata) { var key = GenerateMetadataKey(tableMetadata.DatabaseName, tableMetadata.Name); - if (_columnMetadata.ContainsKey(key)) + if (_columnMetadata.TryGetValue(key, out IEnumerable? metadata)) { - return _columnMetadata[key]; + return metadata; } SetTableSchema(tableMetadata); - return _columnMetadata.ContainsKey(key) - ? _columnMetadata[key] - : Enumerable.Empty(); + return _columnMetadata.TryGetValue(key, out IEnumerable? columnMetadata) + ? columnMetadata : Enumerable.Empty(); } private void SetTableSchema(TableMetadata tableMetadata) @@ -683,9 +679,9 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Kusto Urn = $"{tableKey}.{table.TableName}" }; - if (tableFolders.ContainsKey(tableKey.ToString())) + if (tableFolders.TryGetValue(tableKey.ToString(), out List? tableMetadataList)) { - tableFolders[tableKey.ToString()].Add(tableMetadata); + tableMetadataList.Add(tableMetadata); } else { diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoQueryUtils.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoQueryUtils.cs index 2a8e30fa..65150296 100644 --- a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoQueryUtils.cs +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoQueryUtils.cs @@ -12,7 +12,7 @@ using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; namespace Microsoft.Kusto.ServiceLayer.DataSource { - public static class KustoQueryUtils + public static partial class KustoQueryUtils { public const string StatementSeparator = "\n | "; // Start each statement on a new line. Not required by Kusto, but doing this for readability of scripts generated from here. @@ -30,7 +30,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource } string result = name; - Regex rx = new Regex("[^_a-zA-Z0-9]"); string [] kustoKeywordList = {"and", "anomalychart", "areachart", "asc", "barchart", "between", "bool", "boolean", "by", "columnchart", "consume", "contains", "containscs", "count", "date", "datetime", "default", "desc", "distinct", "double", "dynamic", "endswith", "evaluate", "extend", "false", "filter", "find", "first", "flags", "float", @@ -41,7 +40,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource "take", "time", "timechart", "timeline", "timepivot", "timespan", "to", "top", "toscalar", "true", "union", "unstacked", "viewers", "where", "withsource"}; // add more keywords here - var escapeName = rx.IsMatch(name) || kustoKeywordList.Any(name.Contains) || alwaysEscape; + var escapeName = GetNameRegex().IsMatch(name) || kustoKeywordList.Any(name.Contains) || alwaysEscape; if (escapeName) { if (name.IndexOf('"') > -1) @@ -79,14 +78,14 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource public static void SafeAdd(this Dictionary> dictionary, string key, T metadata) where T : DataSourceObjectMetadata { - if (dictionary.ContainsKey(key)) + if (dictionary.TryGetValue(key, out Dictionary? metadataCollection)) { - if (dictionary[key].ContainsKey(metadata.Name)) + if (metadataCollection.ContainsKey(metadata.Name)) { return; } - - dictionary[key].Add(metadata.Name, metadata); + + metadataCollection.Add(metadata.Name, metadata); } else { @@ -97,14 +96,14 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource public static void SafeAdd(this Dictionary> dictionary, string key, T node) where T : DataSourceObjectMetadata { - if (dictionary.ContainsKey(key)) + if (dictionary.TryGetValue(key, out SortedDictionary? metadataCollection)) { - if (dictionary[key].ContainsKey(node.PrettyName)) + if (metadataCollection.ContainsKey(node.PrettyName)) { return; } - dictionary[key].Add(node.PrettyName, node); + metadataCollection.Add(node.PrettyName, node); } else { @@ -123,9 +122,9 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource public static void AddRange(this ConcurrentDictionary> dictionary, string key, List metadatas) where T : DataSourceObjectMetadata { - if (dictionary.ContainsKey(key)) + if (dictionary.TryGetValue(key, out IEnumerable? value)) { - metadatas.AddRange(dictionary[key]); + metadatas.AddRange(value); } dictionary[key] = metadatas.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase).ToList(); @@ -133,11 +132,16 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource public static string ParseDatabaseName(string databaseName) { - var regex = new Regex(@"(?<=\().+?(?=\))"); + var regex = GetDatabaseNameRegex(); return regex.IsMatch(databaseName) ? regex.Match(databaseName).Value : databaseName; } + + [GeneratedRegex("(?<=\\().+?(?=\\))")] + private static partial Regex GetDatabaseNameRegex(); + [GeneratedRegex("[^_a-zA-Z0-9]")] + private static partial Regex GetNameRegex(); } } diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Monitor/MonitorDataSource.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Monitor/MonitorDataSource.cs index 87b94384..55a72550 100644 --- a/src/Microsoft.Kusto.ServiceLayer/DataSource/Monitor/MonitorDataSource.cs +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Monitor/MonitorDataSource.cs @@ -22,7 +22,7 @@ using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; namespace Microsoft.Kusto.ServiceLayer.DataSource.Monitor { - public class MonitorDataSource : DataSourceBase + public partial class MonitorDataSource : DataSourceBase { private readonly MonitorClient _monitorClient; private readonly IntellisenseClientBase _intellisenseClient; @@ -158,7 +158,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Monitor private string ParseWorkspaceId(string workspace) { - var regex = new Regex(@"(?<=\().+?(?=\))"); + var regex = GetWorkspaceIdRegex(); return regex.IsMatch(workspace) ? regex.Match(workspace).Value @@ -227,5 +227,8 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Monitor } }; } + + [GeneratedRegex("(?<=\\().+?(?=\\))")] + private static partial Regex GetWorkspaceIdRegex(); } } \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/BindingQueue.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/BindingQueue.cs index aee96a0c..aa113406 100644 --- a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/BindingQueue.cs +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/BindingQueue.cs @@ -198,11 +198,9 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices { lock (this._bindingContextLock) { - if (this.BindingContextMap.ContainsKey(key)) + if (this.BindingContextMap.TryGetValue(key, out IBindingContext? bindingContext)) { // disconnect existing connection - var bindingContext = this.BindingContextMap[key]; - // remove key from the map this.BindingContextMap.Remove(key); this.BindingContextTasks.Remove(bindingContext); diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs index 1e20e415..cf6876ac 100644 --- a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs @@ -1011,13 +1011,13 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices /// /// /// Creates a new instance if one doesn't exist - internal ScriptParseInfo GetScriptParseInfo(string uri, bool createIfNotExists = false) + internal ScriptParseInfo? GetScriptParseInfo(string uri, bool createIfNotExists = false) { lock (this.parseMapLock) { - if (this.ScriptParseInfoMap.ContainsKey(uri)) + if (this.ScriptParseInfoMap.TryGetValue(uri, out ScriptParseInfo? scriptParseInfo)) { - return this.ScriptParseInfoMap[uri]; + return scriptParseInfo; } else if (createIfNotExists) { @@ -1091,7 +1091,7 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices } // If there is a single statement on the line, track it so that we can return it regardless of where the user's cursor is - SqlStatement lineStatement = null; + SqlStatement? lineStatement = null; bool? lineHasSingleStatement = null; // check if the batch matches parameters @@ -1125,7 +1125,7 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices if (lineHasSingleStatement == true) { - return lineStatement.Sql; + return lineStatement?.Sql ?? string.Empty; } } } diff --git a/src/Microsoft.Kusto.ServiceLayer/Microsoft.Kusto.ServiceLayer.csproj b/src/Microsoft.Kusto.ServiceLayer/Microsoft.Kusto.ServiceLayer.csproj index bd36a15d..95078846 100644 --- a/src/Microsoft.Kusto.ServiceLayer/Microsoft.Kusto.ServiceLayer.csproj +++ b/src/Microsoft.Kusto.ServiceLayer/Microsoft.Kusto.ServiceLayer.csproj @@ -13,8 +13,8 @@ true portable $(ToolsServiceTargetRuntimes) - - $(NoWarn);SYSLIB1045;CA1311;CA1854 + + $(NoWarn);CS8795 SqlTools Kusto Editor Services Host Protocol Library Provides message types and client/server APIs for the SqlTools Kusto Editor Services JSON protocol. diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/ResultSet.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/ResultSet.cs index 478475af..e74560de 100644 --- a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/ResultSet.cs +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/ResultSet.cs @@ -3,6 +3,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +#nullable disable + using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; using Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage; using Microsoft.Kusto.ServiceLayer.Utility; @@ -24,7 +26,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution /// Class that represents a resultset the was generated from a query. Contains logic for /// storing and retrieving results. Is contained by a Batch class. /// - public class ResultSet : IDisposable + public partial class ResultSet : IDisposable { #region Constants @@ -343,7 +345,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution // Verify the request hasn't been cancelled cancellationToken.ThrowIfCancellationRequested(); - StorageDataReader dataReader = new StorageDataReader(dbDataReader); + var dataReader = new StorageDataReader(dbDataReader); // Open a writer for the file // @@ -478,7 +480,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution } // Create the new task - Task saveAsTask = new Task(async () => + var saveAsTask = new Task(async () => { try { @@ -602,7 +604,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution // sendResultsSemphore.Wait(); - ResultSet currentResultSetSnapshot = (ResultSet) MemberwiseClone(); + var currentResultSetSnapshot = (ResultSet) MemberwiseClone(); if (LastUpdatedSummary == null) // We need to send results available message. { // Fire off results Available task and await it @@ -677,13 +679,12 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution { if (Columns?.Length > 0 && RowCount != 0) { - Regex regex = new Regex(@"({.*?})"); var row = GetRow(0); for (int i = 0; i < Columns.Length; i++) { if (Columns[i].DataTypeName.Equals("nvarchar")) { - if (regex.IsMatch(row[i].DisplayValue)) + if (GetJsonRegex().IsMatch(row[i].DisplayValue)) { Columns[i].IsJson = true; } @@ -726,7 +727,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution // Returning false from .ReadAsync means there aren't any rows. // Create a storage data reader, read it, make sure there were results - StorageDataReader dataReader = new StorageDataReader(dbDataReader); + var dataReader = new StorageDataReader(dbDataReader); if (!await dataReader.ReadAsync(CancellationToken.None)) { throw new InvalidOperationException(SR.QueryServiceResultSetAddNoRows); @@ -742,6 +743,9 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution } } + [GeneratedRegex("({.*?})")] + private static partial Regex GetJsonRegex(); + #endregion } } diff --git a/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingExtensionMethods.cs b/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingExtensionMethods.cs index c2cde43c..4a31ca13 100644 --- a/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingExtensionMethods.cs +++ b/src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingExtensionMethods.cs @@ -99,7 +99,7 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting // Leaving the server name blank will automatically match whatever the server SMO is running against. string urn = string.Format( "Server[@Name='{0}']/Database[@Name='{1}']/{2}[@Name='{3}' {4}]", - server.ToUpper(), + server.ToUpper(System.Globalization.CultureInfo.InvariantCulture), Urn.EscapeString(database), scriptingObject.Type, Urn.EscapeString(scriptingObject.Name), diff --git a/src/Microsoft.Kusto.ServiceLayer/Utility/ResolvedFile.cs b/src/Microsoft.Kusto.ServiceLayer/Utility/ResolvedFile.cs index a369c814..3bb71b78 100644 --- a/src/Microsoft.Kusto.ServiceLayer/Utility/ResolvedFile.cs +++ b/src/Microsoft.Kusto.ServiceLayer/Utility/ResolvedFile.cs @@ -32,12 +32,6 @@ namespace Microsoft.Kusto.ServiceLayer.Utility public bool CanReadFromDisk { get; private set; } - public string LowercaseClientUri - { - get - { - return ClientUri?.ToLower(); - } - } + public string LowercaseClientUri => ClientUri?.ToLower(System.Globalization.CultureInfo.InvariantCulture); } } \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Utility/SqlScriptFormatters/FromSqlScript.cs b/src/Microsoft.Kusto.ServiceLayer/Utility/SqlScriptFormatters/FromSqlScript.cs index ac201576..d040f2c4 100644 --- a/src/Microsoft.Kusto.ServiceLayer/Utility/SqlScriptFormatters/FromSqlScript.cs +++ b/src/Microsoft.Kusto.ServiceLayer/Utility/SqlScriptFormatters/FromSqlScript.cs @@ -14,11 +14,11 @@ namespace Microsoft.Kusto.ServiceLayer.Utility.SqlScriptFormatters /// /// Provides utilities for converting from SQL script syntax into POCOs. /// - public static class FromSqlScript + public static partial class FromSqlScript { // Regex: optionally starts with N, captures string wrapped in single quotes - private static readonly Regex StringRegex = new Regex("^N?'(.*)'$", RegexOptions.Compiled); - private static readonly Regex BracketRegex = new Regex(@"^\[(.*)\]$", RegexOptions.Compiled); + private static readonly Regex StringRegex = GetStringRegex(); + private static readonly Regex BracketRegex = GetBracketRegex(); /// /// Decodes a multipart identifier as used in a SQL script into an array of the multiple @@ -33,8 +33,8 @@ namespace Microsoft.Kusto.ServiceLayer.Utility.SqlScriptFormatters /// public static string[] DecodeMultipartIdentifier(string multipartIdentifier) { - StringBuilder sb = new StringBuilder(); - List namedParts = new List(); + var sb = new StringBuilder(); + var namedParts = new List(); bool insideBrackets = false; bool bracketsClosed = false; for (int i = 0; i < multipartIdentifier.Length; i++) @@ -152,6 +152,11 @@ namespace Microsoft.Kusto.ServiceLayer.Utility.SqlScriptFormatters return value.Replace(new string(escapeCharacter, 2), escapeCharacter.ToString()); } + [GeneratedRegex("^N?'(.*)'$", RegexOptions.Compiled)] + private static partial Regex GetStringRegex(); + [GeneratedRegex("^\\[(.*)\\]$", RegexOptions.Compiled)] + private static partial Regex GetBracketRegex(); + #endregion } } \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/ScriptFile.cs b/src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/ScriptFile.cs index a5132801..0b3cd874 100644 --- a/src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/ScriptFile.cs +++ b/src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/ScriptFile.cs @@ -25,7 +25,7 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace.Contracts /// public string Id { - get { return this.ClientUri.ToLower(); } + get { return this.ClientUri.ToLower(System.Globalization.CultureInfo.InvariantCulture); } } /// diff --git a/src/Microsoft.Kusto.ServiceLayer/Workspace/Workspace.cs b/src/Microsoft.Kusto.ServiceLayer/Workspace/Workspace.cs index 4dae33a7..35099358 100644 --- a/src/Microsoft.Kusto.ServiceLayer/Workspace/Workspace.cs +++ b/src/Microsoft.Kusto.ServiceLayer/Workspace/Workspace.cs @@ -21,7 +21,7 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace /// Manages a "workspace" of script files that are open for a particular /// editing session. Also helps to navigate references between ScriptFiles. /// - public class Workspace : IDisposable + public partial class Workspace : IDisposable { #region Private Fields @@ -115,8 +115,8 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace } // This method allows FileNotFoundException to bubble up // if the file isn't found. - using (FileStream fileStream = new FileStream(resolvedFile.FilePath, FileMode.Open, FileAccess.Read)) - using (StreamReader streamReader = new StreamReader(fileStream, Encoding.UTF8)) + using (var fileStream = new FileStream(resolvedFile.FilePath, FileMode.Open, FileAccess.Read)) + using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { scriptFile = new ScriptFile(resolvedFile.FilePath, resolvedFile.ClientUri,streamReader); @@ -148,7 +148,7 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace // Client sent the path in URI format, extract the local path and trim // any extraneous slashes - Uri fileUri = new Uri(clientUri); + var fileUri = new Uri(clientUri); filePath = fileUri.LocalPath; if (filePath.StartsWith("//") || filePath.StartsWith("\\\\") || filePath.StartsWith("/")) { @@ -206,7 +206,7 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace return path; } - return Regex.Replace(path, @"`(?=[ \[\]])", ""); + return GetEscapeRegex().Replace(path, ""); } /// @@ -361,6 +361,9 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace { } + [GeneratedRegex("`(?=[ \\[\\]])")] + private static partial Regex GetEscapeRegex(); + #endregion } } diff --git a/src/Microsoft.SqlTools.Credentials/Microsoft.SqlTools.Credentials.csproj b/src/Microsoft.SqlTools.Credentials/Microsoft.SqlTools.Credentials.csproj index 4020f4ef..2959b390 100644 --- a/src/Microsoft.SqlTools.Credentials/Microsoft.SqlTools.Credentials.csproj +++ b/src/Microsoft.SqlTools.Credentials/Microsoft.SqlTools.Credentials.csproj @@ -1,45 +1,47 @@ - - MicrosoftSqlToolsCredentials - Exe - false - false - false - false - false - false - $(DefineConstants);NETCOREAPP1_0 - true - true - $(ToolsServiceTargetRuntimes) - SqlTools Editor Services Credentials Manager Library - Provides message types and client/server APIs for the SqlTools Credential Services JSON protocol. - + + MicrosoftSqlToolsCredentials + Exe + false + false + false + false + false + false + $(DefineConstants);NETCOREAPP1_0 + true + true + $(ToolsServiceTargetRuntimes) + SqlTools Editor Services Credentials Manager Library + Provides message types and client/server APIs for the SqlTools Credential Services JSON protocol. + $(NoWarn);SYSLIB1054 - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.SqlTools.ManagedBatchParser/BatchParser/BatchParserWrapper.cs b/src/Microsoft.SqlTools.ManagedBatchParser/BatchParser/BatchParserWrapper.cs index aedb08e1..f778ef30 100644 --- a/src/Microsoft.SqlTools.ManagedBatchParser/BatchParser/BatchParserWrapper.cs +++ b/src/Microsoft.SqlTools.ManagedBatchParser/BatchParser/BatchParserWrapper.cs @@ -408,7 +408,7 @@ namespace Microsoft.SqlTools.ServiceLayer.BatchParser /// /// Internal implementation class to implement IBatchEventHandlers /// - internal class BatchEventNotificationHandler : IBatchEventsHandler + internal sealed class BatchEventNotificationHandler : IBatchEventsHandler { public void OnBatchError(object sender, BatchErrorEventArgs args) { @@ -477,7 +477,7 @@ namespace Microsoft.SqlTools.ServiceLayer.BatchParser } #endregion - private class BatchInfo + private sealed class BatchInfo { public BatchInfo(int startLine, int startColumn, string batchText, SqlCmdCommand sqlCmdCommand, int repeatCount = 1) { diff --git a/src/Microsoft.SqlTools.ManagedBatchParser/Microsoft.SqlTools.ManagedBatchParser.csproj b/src/Microsoft.SqlTools.ManagedBatchParser/Microsoft.SqlTools.ManagedBatchParser.csproj index ce687693..6b9ec092 100644 --- a/src/Microsoft.SqlTools.ManagedBatchParser/Microsoft.SqlTools.ManagedBatchParser.csproj +++ b/src/Microsoft.SqlTools.ManagedBatchParser/Microsoft.SqlTools.ManagedBatchParser.csproj @@ -32,7 +32,7 @@ $(VersionPrefix) $(VersionPrefix) $(VersionPrefix) - + $(NoWarn);CA1852 diff --git a/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/AmbientSettings.cs b/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/AmbientSettings.cs index d11807ed..0aa707c5 100644 --- a/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/AmbientSettings.cs +++ b/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/AmbientSettings.cs @@ -374,7 +374,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection /// /// This class is used as value in the dictionary to ensure that the type of value is correct. /// - private class AmbientValue + private sealed class AmbientValue { private readonly Type _type; private readonly bool _isTypeNullable; diff --git a/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/CachedServerInfo.cs b/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/CachedServerInfo.cs index 5d785ff6..7f64aeed 100644 --- a/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/CachedServerInfo.cs +++ b/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/CachedServerInfo.cs @@ -45,7 +45,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection } #region CacheKey implementation - internal class CacheKey : IEquatable + internal sealed class CacheKey : IEquatable { private string dataSource; private string dbName; diff --git a/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/RetryPolicy.cs b/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/RetryPolicy.cs index ff15a1a4..e6551be5 100644 --- a/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/RetryPolicy.cs +++ b/src/Microsoft.SqlTools.ManagedBatchParser/ReliableConnection/RetryPolicy.cs @@ -407,7 +407,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection } } - internal class ExponentialDelayRetryPolicy : RetryPolicy + internal sealed class ExponentialDelayRetryPolicy : RetryPolicy { private readonly int _maxRetryCount; private readonly double _intervalFactor; diff --git a/src/Microsoft.SqlTools.ResourceProvider.DefaultImpl/Microsoft.SqlTools.ResourceProvider.DefaultImpl.csproj b/src/Microsoft.SqlTools.ResourceProvider.DefaultImpl/Microsoft.SqlTools.ResourceProvider.DefaultImpl.csproj index 9eae498b..70d80f68 100644 --- a/src/Microsoft.SqlTools.ResourceProvider.DefaultImpl/Microsoft.SqlTools.ResourceProvider.DefaultImpl.csproj +++ b/src/Microsoft.SqlTools.ResourceProvider.DefaultImpl/Microsoft.SqlTools.ResourceProvider.DefaultImpl.csproj @@ -10,7 +10,7 @@ Provides the default for SqlTools applications. � Microsoft Corporation. All rights reserved. - + $(NoWarn);CA1852 diff --git a/src/Microsoft.SqlTools.ResourceProvider/Microsoft.SqlTools.ResourceProvider.csproj b/src/Microsoft.SqlTools.ResourceProvider/Microsoft.SqlTools.ResourceProvider.csproj index af33038f..7866c988 100644 --- a/src/Microsoft.SqlTools.ResourceProvider/Microsoft.SqlTools.ResourceProvider.csproj +++ b/src/Microsoft.SqlTools.ResourceProvider/Microsoft.SqlTools.ResourceProvider.csproj @@ -12,15 +12,15 @@ false false $(ToolsServiceTargetRuntimes) - - $(NoWarn);CA1852 + + $(NoWarn);CA1852 TRACE;DEBUG;NETCOREAPP1_0;NETCOREAPP2_0 - + diff --git a/src/Microsoft.SqlTools.ResourceProvider/Program.cs b/src/Microsoft.SqlTools.ResourceProvider/Program.cs index 2716e65f..f5d45130 100644 --- a/src/Microsoft.SqlTools.ResourceProvider/Program.cs +++ b/src/Microsoft.SqlTools.ResourceProvider/Program.cs @@ -16,7 +16,7 @@ namespace Microsoft.SqlTools.ResourceProvider /// /// Main application class for the executable that supports the resource provider and identity services /// - internal class Program + internal sealed class Program { private const string ServiceName = "SqlToolsResourceProviderService.exe"; diff --git a/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/AzureSqlDbHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/AzureSqlDbHelper.cs index 49b1dd2b..a1585636 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/AzureSqlDbHelper.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/AzureSqlDbHelper.cs @@ -3,8 +3,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics; @@ -51,9 +49,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin return Name.GetHashCode(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - return obj is AzureEdition && ((AzureEdition)obj).Name.Equals(Name); + return obj is AzureEdition edition && edition.Name.Equals(Name); } public static bool operator ==(AzureEdition left, AzureEdition right) @@ -82,7 +80,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin var azureEdition = AzureServiceObjectiveInfo.Keys.FirstOrDefault( key => key.Name.ToLowerInvariant().Equals(edition.ToLowerInvariant())); - if (azureEdition != null) + if (azureEdition! != null) { return azureEdition; } @@ -358,9 +356,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin /// StorageAccountType string value for the current storageType public static string GetStorageAccountTypeFromString(string storageAccountType) { - if (bsrAPIToUIValueMapping.ContainsKey(storageAccountType)) + if (bsrAPIToUIValueMapping.TryGetValue(storageAccountType, out string? value)) { - return bsrAPIToUIValueMapping[storageAccountType]; + return value; } return storageAccountType; } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Agent/AgentService.cs b/src/Microsoft.SqlTools.ServiceLayer/Agent/AgentService.cs index 65e6e9ed..a9e2e476 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Agent/AgentService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Agent/AgentService.cs @@ -1100,7 +1100,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent } const string UrnFormatStr = "Server/JobServer[@Name='{0}']/Job[@Name='{1}']/Schedule[@Name='{2}']"; - string serverName = dataContainer.Server.Name.ToUpper(); + string serverName = dataContainer.Server.Name.ToUpper(System.Globalization.CultureInfo.InvariantCulture); string scheduleUrn = string.Format(UrnFormatStr, serverName, jobData.Job.Name, schedule.Name); STParameters param = new STParameters(dataContainer.Document); @@ -1132,7 +1132,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo); dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); - XmlDocument jobDoc = CreateJobXmlDocument(dataContainer.Server.Name.ToUpper(), jobName); + XmlDocument jobDoc = CreateJobXmlDocument(dataContainer.Server.Name.ToUpper(System.Globalization.CultureInfo.InvariantCulture), jobName); dataContainer.Init(jobDoc.InnerXml); STParameters param = new STParameters(dataContainer.Document); @@ -1487,9 +1487,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent { string jobRuntime = jobHistory.RunDate.ToString("yyyyMMddHHmmss"); AgentNotebookHistoryInfo notebookHistory = jobHistory; - if (notebookHistoriesDict.ContainsKey(jobRuntime)) + if (notebookHistoriesDict.TryGetValue(jobRuntime, out DataRow dataRow)) { - notebookHistory.MaterializedNotebookId = (int)notebookHistoriesDict[jobRuntime]["materialized_id"]; + notebookHistory.MaterializedNotebookId = (int)dataRow["materialized_id"]; notebookHistory.MaterializedNotebookErrorInfo = notebookHistoriesDict[jobRuntime]["notebook_error"] as string; notebookHistory.MaterializedNotebookName = notebookHistoriesDict[jobRuntime]["notebook_name"] as string; notebookHistory.MaterializedNotebookPin = (bool)notebookHistoriesDict[jobRuntime]["pin"]; diff --git a/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/JobStepSubSystems.cs b/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/JobStepSubSystems.cs index 06afdcf6..f9714562 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/JobStepSubSystems.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/JobStepSubSystems.cs @@ -3,8 +3,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -#nullable disable - using System; using System.Collections.Generic; using System.ComponentModel; @@ -32,54 +30,56 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent { this.data = data; var availableSystems = - dataContainer.Server.JobServer.EnumSubSystems() + dataContainer.Server?.JobServer.EnumSubSystems() .Rows.OfType() .Select(r => (AgentSubSystem)Convert.ToInt32(r["subsystem_id"])); - - foreach (var agentSubSystemId in availableSystems) + if (availableSystems != null) { - var agentSubSystem = CreateJobStepSubSystem(agentSubSystemId, dataContainer, data); - // The server might have some new subsystem we don't know about, just ignore it. - if (agentSubSystem != null) + foreach (var agentSubSystemId in availableSystems) { - subSystems[agentSubSystemId] = agentSubSystem; + var agentSubSystem = CreateJobStepSubSystem(agentSubSystemId, dataContainer, data); + // The server might have some new subsystem we don't know about, just ignore it. + if (agentSubSystem != null) + { + subSystems[agentSubSystemId] = agentSubSystem; + } } - } + } } public JobStepSubSystem[] AvailableSubSystems { - get { return this.subSystems.Keys.OrderBy(k => (int) k).Select(k => this.subSystems[k]).ToArray(); } + get { return this.subSystems.Keys.OrderBy(k => (int)k).Select(k => this.subSystems[k]).ToArray(); } } public JobStepSubSystem Lookup(AgentSubSystem key) { JobStepSubSystem rv = null; - if (this.subSystems.ContainsKey(key)) + if (this.subSystems.TryGetValue(key, out JobStepSubSystem? value)) { - return this.subSystems[key]; + return value; } return rv; } - private static TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof (AgentSubSystem)); + private static TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(AgentSubSystem)); // Returns name of the subsystem for a given enum value public static string LookupFriendlyName(AgentSubSystem key) { return (string)typeConverter.ConvertToString((Enum)key); } - + // Returns name of the subsystem for a given enum value public static string LookupName(AgentSubSystem key) { // Have to subtract first enum value to bring the // index to 0-based index - return typeConverter.ConvertToInvariantString((Enum) key); + return typeConverter.ConvertToInvariantString((Enum)key); } private static JobStepSubSystem CreateJobStepSubSystem( - AgentSubSystem agentSubSystem, - CDataContainer dataContainer, + AgentSubSystem agentSubSystem, + CDataContainer dataContainer, JobStepData data) { switch (agentSubSystem) diff --git a/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/JobStepsActions.cs b/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/JobStepsActions.cs index da78b0d0..b5392121 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/JobStepsActions.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/JobStepsActions.cs @@ -95,7 +95,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent if (jobData.Job != null) { const string UrnFormatStr = "Server/JobServer[@Name='{0}']/Job[@Name='{1}']/Step[@Name='{2}']"; - string serverName = this.DataContainer.Server.Name.ToUpper(); + string serverName = this.DataContainer.Server.Name.ToUpper(System.Globalization.CultureInfo.InvariantCulture); string urn = string.Format(UrnFormatStr, serverName, jobData.Job.Name, stepName); jobStep = jobData.Job.Parent.Parent.GetSmoObject(urn) as JobStep; } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/ScheduleData.cs b/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/ScheduleData.cs index 030e87f6..c5dc8776 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/ScheduleData.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/ScheduleData.cs @@ -24,7 +24,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent /// simple job schedule structure. /// - public struct SimpleJobSchedule + public partial struct SimpleJobSchedule { #region consts private const int EndOfDay = 235959; @@ -44,7 +44,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent private FrequencyTypes frequencyTypes; private FrequencySubDayTypes frequencySubDayTypes; private FrequencyRelativeIntervals frequencyRelativeIntervals; - private System.Boolean isEnabled; + private bool isEnabled; #endregion #region Init @@ -100,7 +100,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent public static DateTime ConvertIntToDateTime(int source) { return new DateTime(source / 10000 - , (source / 100) % 100 + , source / 100 % 100 , source % 100); } /// @@ -126,7 +126,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent public static TimeSpan ConvertIntToTimeSpan(int source) { return new TimeSpan(source / 10000 - , (source / 100) % 100 + , source / 100 % 100 , source % 100); } /// @@ -150,13 +150,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent /// JobScheduleData object public JobScheduleData ToJobScheduleData() { - JobScheduleData data = new JobScheduleData(); + var data = new JobScheduleData(); data.Name = this.Name; data.Enabled = this.IsEnabled; - data.ActiveStartDate = SimpleJobSchedule.ConvertIntToDateLocalized(this.ActiveStartDate); - data.ActiveStartTime = SimpleJobSchedule.ConvertIntToTimeSpan(this.ActiveStartTimeOfDay); - data.ActiveEndDate = SimpleJobSchedule.ConvertIntToDateLocalized(this.ActiveEndDate); - data.ActiveEndTime = SimpleJobSchedule.ConvertIntToTimeSpan(this.ActiveEndTimeOfDay); + data.ActiveStartDate = ConvertIntToDateLocalized(this.ActiveStartDate); + data.ActiveStartTime = ConvertIntToTimeSpan(this.ActiveStartTimeOfDay); + data.ActiveEndDate = ConvertIntToDateLocalized(this.ActiveEndDate); + data.ActiveEndTime = ConvertIntToTimeSpan(this.ActiveEndTimeOfDay); data.FrequencyTypes = this.FrequencyTypes; data.FrequencyInterval = this.FrequencyInterval; data.FrequencyRecurranceFactor = this.FrequencyRecurrenceFactor; @@ -173,15 +173,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent /// new SimpleJobSchedule public static SimpleJobSchedule FromJobScheduleData(JobScheduleData source) { - SimpleJobSchedule schedule = new SimpleJobSchedule(); + var schedule = new SimpleJobSchedule(); schedule.Name = source.Name; schedule.ID = source.ID; schedule.IsEnabled = source.Enabled; - schedule.ActiveStartDate = SimpleJobSchedule.ConvertDateTimeToInt(source.ActiveStartDate); - schedule.ActiveStartTimeOfDay = SimpleJobSchedule.ConvertTimeSpanToInt(source.ActiveStartTime); - schedule.ActiveEndDate = SimpleJobSchedule.ConvertDateTimeToInt(source.ActiveEndDate); - schedule.ActiveEndTimeOfDay = SimpleJobSchedule.ConvertTimeSpanToInt(source.ActiveEndTime); + schedule.ActiveStartDate = ConvertDateTimeToInt(source.ActiveStartDate); + schedule.ActiveStartTimeOfDay = ConvertTimeSpanToInt(source.ActiveStartTime); + schedule.ActiveEndDate = ConvertDateTimeToInt(source.ActiveEndDate); + schedule.ActiveEndTimeOfDay = ConvertTimeSpanToInt(source.ActiveEndTime); schedule.FrequencyTypes = source.FrequencyTypes; schedule.FrequencyInterval = source.FrequencyInterval; schedule.FrequencyRecurrenceFactor = source.FrequencyRecurranceFactor; @@ -293,7 +293,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent return string.Empty; } - StringBuilder daysOfWeek = new StringBuilder(); + var daysOfWeek = new StringBuilder(); // Start matching with Monday. GetLocalizedDaysOfWeek() must start with Monday too. WeekDays dayOfWeek = WeekDays.Monday; foreach (string localizedDayOfWeek in GetLocalizedDaysOfWeek()) @@ -309,7 +309,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent // There's no easy way to advance to the next enum value, so since we know // it's a bitfield mask we do a left shift ourselves. - int nextDay = ((int)dayOfWeek) << 1; + int nextDay = (int)dayOfWeek << 1; dayOfWeek = (WeekDays)nextDay; if (dayOfWeek > WeekDays.Saturday) { @@ -449,7 +449,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent { get { - MonthlyRelativeWeekDays relativeDays = (MonthlyRelativeWeekDays) this.FrequencyInterval; + var relativeDays = (MonthlyRelativeWeekDays) this.FrequencyInterval; switch (relativeDays) { @@ -671,10 +671,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent /// string ExpandFormatString(string format) { - StringBuilder stringBuilder = new StringBuilder(); + var stringBuilder = new StringBuilder(); int lastIndex = 0; - MatchCollection matches = Regex.Matches(format, @"\{(?\w+)\}"); + MatchCollection matches = GetPropertyDescriptorRegex().Matches(format); if (matches.Count > 0) { @@ -687,7 +687,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent if (property != null) { object propertyValue = property.GetValue(this); - propertyValue = propertyValue != null ? propertyValue.ToString() : String.Empty; + propertyValue = propertyValue != null ? propertyValue.ToString() : string.Empty; stringBuilder.Append(format.Substring(lastIndex, match.Index - lastIndex)); stringBuilder.Append(propertyValue as string); @@ -705,6 +705,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent return new string[] { "SR.Monday", "SR.Tuesday", "SR.Wednesday", "SR.Thursday", "SR.Friday", "SR.Saturday", "SR.Sunday" }; } + [GeneratedRegex("\\{(?\\w+)\\}")] + private static partial Regex GetPropertyDescriptorRegex(); + #endregion } diff --git a/src/Microsoft.SqlTools.ServiceLayer/AzureFunctions/AzureFunctionsUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/AzureFunctions/AzureFunctionsUtils.cs index 237c9e33..b084810b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/AzureFunctions/AzureFunctionsUtils.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/AzureFunctions/AzureFunctionsUtils.cs @@ -102,7 +102,7 @@ namespace Microsoft.SqlTools.ServiceLayer.AzureFunctions return a.ArgumentList ?.Arguments .Where(a => a.Expression.Kind() == SyntaxKind.StringLiteralExpression && a.NameEquals == null) // Operations are string literals who don't have a name (Route is always a named param) - .Select(a => a.ToString().TrimStringQuotes().ToUpper()) // upper case for consistent naming + .Select(a => a.ToString().TrimStringQuotes().ToUpper(System.Globalization.CultureInfo.InvariantCulture)) // upper case for consistent naming .ToArray(); } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs index 2ad00146..b365a159 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs @@ -1420,7 +1420,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection { // Secure Enclaves is not mapped to SqlConnection, it's only used for throwing validation errors // when Enclave Attestation Protocol is missing. - switch (connectionDetails.SecureEnclaves.ToUpper()) + switch (connectionDetails.SecureEnclaves.ToUpper(CultureInfo.InvariantCulture)) { case "ENABLED": if (string.IsNullOrEmpty(connectionDetails.EnclaveAttestationProtocol)) @@ -1437,7 +1437,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection if (!string.IsNullOrEmpty(connectionDetails.EnclaveAttestationProtocol)) { if (connectionBuilder.ColumnEncryptionSetting != SqlConnectionColumnEncryptionSetting.Enabled - || string.IsNullOrEmpty(connectionDetails.SecureEnclaves) || connectionDetails.SecureEnclaves.ToUpper() == "DISABLED") + || string.IsNullOrEmpty(connectionDetails.SecureEnclaves) || connectionDetails.SecureEnclaves.ToUpper(CultureInfo.InvariantCulture) == "DISABLED") { throw new ArgumentException(SR.ConnectionServiceConnStringInvalidAlwaysEncryptedOptionCombination); } @@ -1454,7 +1454,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection if (!string.IsNullOrEmpty(connectionDetails.EnclaveAttestationUrl)) { if (connectionBuilder.ColumnEncryptionSetting != SqlConnectionColumnEncryptionSetting.Enabled - || string.IsNullOrEmpty(connectionDetails.SecureEnclaves) || connectionDetails.SecureEnclaves.ToUpper() == "DISABLED") + || string.IsNullOrEmpty(connectionDetails.SecureEnclaves) || connectionDetails.SecureEnclaves.ToUpper(CultureInfo.InvariantCulture) == "DISABLED") { throw new ArgumentException(SR.ConnectionServiceConnStringInvalidAlwaysEncryptedOptionCombination); } diff --git a/src/Microsoft.SqlTools.ServiceLayer/DacFx/GetObjectsFromTSqlModelOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/DacFx/GetObjectsFromTSqlModelOperation.cs index 53643589..e6eaa784 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DacFx/GetObjectsFromTSqlModelOperation.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DacFx/GetObjectsFromTSqlModelOperation.cs @@ -65,7 +65,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx /// public static ModelTypeClass MapType(string type) { - switch (type.ToLower()) + switch (type.ToLower(System.Globalization.CultureInfo.InvariantCulture)) { case "table": return ModelSchema.Table; diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreOptionFactory.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreOptionFactory.cs index 3dbb9ee6..6538a653 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreOptionFactory.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreOptionFactory.cs @@ -3,8 +3,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics; @@ -49,9 +47,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation /// public RestorePlanDetailInfo CreateOptionInfo(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject) { - if(optionBuilders.ContainsKey(optionKey)) + if (optionBuilders.TryGetValue(optionKey, out OptionBuilder? value)) { - return Create(optionKey, restoreDataObject, optionBuilders[optionKey]); + return Create(optionKey, restoreDataObject, value); } else { @@ -68,9 +66,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation /// public void UpdateOption(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject, RestorePlanDetailInfo optionInfo) { - if (optionBuilders.ContainsKey(optionKey)) + if (optionBuilders.TryGetValue(optionKey, out OptionBuilder? value)) { - var builder = optionBuilders[optionKey]; + var builder = value; var currentValue = builder.CurrentValueFunction(restoreDataObject); var defaultValue = builder.DefaultValueFunction(restoreDataObject); var validateResult = builder.ValidateFunction(restoreDataObject, currentValue, defaultValue); @@ -102,9 +100,8 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation { if (restoreDataObject != null) { - if (optionBuilders.ContainsKey(optionKey)) + if (optionBuilders.TryGetValue(optionKey, out OptionBuilder? builder)) { - var builder = optionBuilders[optionKey]; if (restoreDataObject.RestoreParams != null && restoreDataObject.RestoreParams.Options.ContainsKey(optionKey)) { try @@ -149,15 +146,14 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation public string ValidateOption(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject) { string errorMessage = string.Empty; - if (optionBuilders.ContainsKey(optionKey)) + if (optionBuilders.TryGetValue(optionKey, out OptionBuilder? builder)) { - var builder = optionBuilders[optionKey]; var currentValue = builder.CurrentValueFunction(restoreDataObject); var defaultValue = builder.DefaultValueFunction(restoreDataObject); OptionValidationResult result = optionBuilders[optionKey].ValidateFunction(restoreDataObject, currentValue, defaultValue); if (result.IsReadOnly) { - if(!ValueEqualsDefault(currentValue, defaultValue)) + if (!ValueEqualsDefault(currentValue, defaultValue)) { builder.SetValueFunction(restoreDataObject, defaultValue); errorMessage = $"{optionKey} is ready only and cannot be modified"; @@ -180,15 +176,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation private bool ValueEqualsDefault(object currentValue, object defaultValue) { - if(currentValue == null && defaultValue == null) + if (currentValue == null) { - return true; + return defaultValue == null; } - if(currentValue == null && defaultValue != null) - { - return false; - } - if (currentValue != null && defaultValue == null) + else if (defaultValue == null) { return false; } @@ -200,311 +192,311 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation { Register(RestoreOptionsHelper.RelocateDbFiles, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return false; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.RelocateAllFiles; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult { IsReadOnly = restoreDataObject.DbFiles.Count == 0 }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.RelocateAllFiles = restoreDataObject.RestoreParams.GetOptionValue(RestoreOptionsHelper.RelocateDbFiles); return true; } - }); + )); Register(RestoreOptionsHelper.DataFileFolder, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.DefaultDataFileFolder; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.DataFilesFolder; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult { IsReadOnly = !restoreDataObject.RelocateAllFiles }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.DataFilesFolder = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.LogFileFolder, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.DefaultLogFileFolder; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.LogFilesFolder; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult { IsReadOnly = !restoreDataObject.RelocateAllFiles }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.LogFilesFolder = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.ReplaceDatabase, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return false; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.RestoreOptions.ReplaceDatabase; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult(); }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.RestoreOptions.ReplaceDatabase = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.KeepReplication, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return false; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.RestoreOptions.KeepReplication; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult() { IsReadOnly = restoreDataObject.RestoreOptions.RecoveryState == DatabaseRecoveryState.WithNoRecovery }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.RestoreOptions.KeepReplication = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.SetRestrictedUser, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return false; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.RestoreOptions.SetRestrictedUser; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult() { }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.RestoreOptions.SetRestrictedUser = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.RecoveryState, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return DatabaseRecoveryState.WithRecovery.ToString(); }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.RestoreOptions.RecoveryState.ToString(); }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult() { }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.RestoreOptions.RecoveryState = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.StandbyFile, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.DefaultStandbyFile; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.RestoreOptions.StandByFile; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult() { IsReadOnly = restoreDataObject.RestoreOptions.RecoveryState != DatabaseRecoveryState.WithStandBy }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.RestoreOptions.StandByFile = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.BackupTailLog, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.IsTailLogBackupPossible; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.BackupTailLog; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult() { IsReadOnly = !restoreDataObject.IsTailLogBackupPossible }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.BackupTailLog = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.TailLogBackupFile, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.DefaultTailLogbackupFile; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.TailLogBackupFile; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult() { IsReadOnly = !restoreDataObject.BackupTailLog | !restoreDataObject.IsTailLogBackupPossible }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.TailLogBackupFile = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.TailLogWithNoRecovery, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.IsTailLogBackupWithNoRecoveryPossible; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.TailLogWithNoRecovery; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult() { IsReadOnly = !restoreDataObject.BackupTailLog | !restoreDataObject.IsTailLogBackupWithNoRecoveryPossible }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.TailLogWithNoRecovery = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.CloseExistingConnections, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return false; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.CloseExistingConnections; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult() { IsReadOnly = !restoreDataObject.CanDropExistingConnections }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.CloseExistingConnections = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.SourceDatabaseName, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.DefaultSourceDbName; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.SourceDatabaseName; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { string errorMessage = string.Empty; var sourceDbNames = restoreDataObject.SourceDbNames; @@ -514,41 +506,41 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation } return new OptionValidationResult() { - ErrorMessage = errorMessage + ErrorMessage = errorMessage }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.SourceDatabaseName = GetValueAs(value); return true; } - }); + )); Register(RestoreOptionsHelper.TargetDatabaseName, new OptionBuilder - { - DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + ( + defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.OverwriteTargetDatabase ? restoreDataObject.DefaultSourceDbName : restoreDataObject.DefaultTargetDbName; }, - CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) => + currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) => { return restoreDataObject.TargetDatabaseName; }, - ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => + validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) => { return new OptionValidationResult() { IsReadOnly = false }; }, - SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => + setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) => { restoreDataObject.TargetDatabaseName = GetValueAs(value); return true; } - }); + )); } internal T GetValueAs(object value) @@ -562,7 +554,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation } private RestorePlanDetailInfo Create( - string optionKey, + string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject, OptionBuilder optionBuilder) { @@ -587,6 +579,14 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation public Func ValidateFunction { get; set; } public Func CurrentValueFunction { get; set; } public Func SetValueFunction { get; set; } + + public OptionBuilder(Func defaultValueFunction, Func validateFunction, Func currentValueFunction, Func setValueFunction) + { + this.DefaultValueFunction = defaultValueFunction; + this.ValidateFunction = validateFunction; + this.CurrentValueFunction = currentValueFunction; + this.SetValueFunction = setValueFunction; + } } internal class OptionValidationResult diff --git a/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/CellUpdate.cs b/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/CellUpdate.cs index d456664a..cd81e505 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/CellUpdate.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/CellUpdate.cs @@ -18,11 +18,11 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement /// /// Representation of a cell that should have a value inserted or updated /// - public sealed class CellUpdate + public sealed partial class CellUpdate { private const string NullString = @"NULL"; private const string TextNullString = @"'NULL'"; - private static readonly Regex HexRegex = new Regex("0x[0-9A-F]+", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex HexRegex = GetCharacterRegex(); private static readonly TimeSpan MaxTimespan = TimeSpan.FromHours(24); /// @@ -231,7 +231,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement private void ProcessTimespanColumn(string valueAsString) { - TimeSpan ts = TimeSpan.Parse(valueAsString, CultureInfo.CurrentCulture); + var ts = TimeSpan.Parse(valueAsString, CultureInfo.CurrentCulture); if (ts >= MaxTimespan) { throw new InvalidOperationException(SR.EditDataTimeOver24Hrs); @@ -270,6 +270,9 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement ValueAsString = valueAsString; } + [GeneratedRegex("0x[0-9A-F]+", RegexOptions.IgnoreCase | RegexOptions.Compiled)] + private static partial Regex GetCharacterRegex(); + #endregion } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ShowPlan/DataReaderNodeBuilder.cs b/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ShowPlan/DataReaderNodeBuilder.cs index b91207a6..0e124029 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ShowPlan/DataReaderNodeBuilder.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ShowPlan/DataReaderNodeBuilder.cs @@ -18,7 +18,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan /// /// Base class for building hierarchy of Graph objects from ShowPlan Record Set /// - internal abstract class DataReaderNodeBuilder: INodeBuilder + internal abstract partial class DataReaderNodeBuilder: INodeBuilder { #region Constructor @@ -41,7 +41,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan /// An array of AnalysisServices Graph objects. public ShowPlanGraph[] Execute(object dataSource) { - IDataReader reader = dataSource as IDataReader; + var reader = dataSource as IDataReader; if (reader == null) { @@ -49,7 +49,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan throw new ArgumentException(SR.Keys.UnknownShowPlanSource); } - List graphs = new List(); + var graphs = new List(); Dictionary currentGraphNodes = null; NodeBuilderContext context = null; @@ -174,7 +174,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan for (int i = 0; i < count; i++) { - if (names[i] != null && !((values[i] is DBNull) || values[i] == null)) + if (names[i] != null && !(values[i] is DBNull || values[i] == null)) { node[names[i]] = values[i]; } @@ -220,7 +220,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan string argument = node["Argument"] as string; if (argument != null) { - Match match = argumentObjectExpression.Match(argument); + Match match = GetargumentObjectExpressionRegex().Match(argument); if (match != Match.Empty) { node["Object"] = match.Groups["Object"].Value; @@ -236,8 +236,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan } // Remove spaces and other special characters from physical and logical names - physicalOpType = operatorReplaceExpression.Replace(physicalOpType, ""); - logicalOpType = operatorReplaceExpression.Replace(logicalOpType, ""); + physicalOpType = GetOperatorReplaceExpressionRegex().Replace(physicalOpType, ""); + logicalOpType = GetOperatorReplaceExpressionRegex().Replace(logicalOpType, ""); Operation physicalOp = OperationTable.GetPhysicalOperation(physicalOpType); Operation logicalOp = OperationTable.GetLogicalOperation(logicalOpType); @@ -290,8 +290,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan #region Private members - private static Regex operatorReplaceExpression = new Regex(@"[ \-]", RegexOptions.CultureInvariant | RegexOptions.Compiled); - private static Regex argumentObjectExpression = new Regex(@"OBJECT:\((?[^\)]*)\)", RegexOptions.CultureInvariant | RegexOptions.Compiled); + [GeneratedRegex("[ \\-]", RegexOptions.Compiled | RegexOptions.CultureInvariant)] + private static partial Regex GetOperatorReplaceExpressionRegex(); + + [GeneratedRegex("OBJECT:\\((?[^\\)]*)\\)", RegexOptions.Compiled | RegexOptions.CultureInvariant)] + private static partial Regex GetargumentObjectExpressionRegex(); #endregion } diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/BindingQueue.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/BindingQueue.cs index f9cd1939..54246400 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/BindingQueue.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/BindingQueue.cs @@ -191,10 +191,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices { lock (this.bindingContextLock) { - if (this.BindingContextMap.ContainsKey(key)) + if (this.BindingContextMap.TryGetValue(key, out IBindingContext? bindingContext)) { // disconnect existing connection - var bindingContext = this.BindingContextMap[key]; if (bindingContext.ServerConnection != null && bindingContext.ServerConnection.IsOpen) { // Disconnecting can take some time so run it in a separate task so that it doesn't block removal diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Completion/SqlCompletionItem.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Completion/SqlCompletionItem.cs index 3c9674b1..5105c75f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Completion/SqlCompletionItem.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Completion/SqlCompletionItem.cs @@ -19,9 +19,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion /// /// Creates a completion item from SQL parser declaration item /// - public class SqlCompletionItem + public partial class SqlCompletionItem { - private static Regex ValidSqlNameRegex = new Regex(@"^[\p{L}_@#][\p{L}\p{N}@$#_]{0,127}$"); + [GeneratedRegex("^[\\p{L}_@#][\\p{L}\\p{N}@$#_]{0,127}$")] + private static partial Regex GetValidSqlNameRegex(); private static DelimitedIdentifier BracketedIdentifiers = new DelimitedIdentifier { Start = "[", End = "]" }; private static DelimitedIdentifier FunctionPostfix = new DelimitedIdentifier { Start = "", End = "()" }; private static DelimitedIdentifier[] DelimitedIdentifiers = @@ -79,7 +80,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion case DeclarationType.Schema: // Only quote if we need to - i.e. if this isn't a valid name (has characters that need escaping such as [) // or if it's a reserved word - if (!ValidSqlNameRegex.IsMatch(DeclarationTitle) || AutoCompleteHelper.IsReservedWord(InsertText)) + if (!GetValidSqlNameRegex().IsMatch(DeclarationTitle) || AutoCompleteHelper.IsReservedWord(InsertText)) { InsertText = WithDelimitedIdentifier(BracketedIdentifiers, DeclarationTitle); } @@ -197,7 +198,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion int startColumn, int endColumn) { - CompletionItem item = new CompletionItem() + var item = new CompletionItem() { Label = label, Kind = kind, diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs index 65474bdf..b85f2680 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs @@ -1869,10 +1869,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices { lock (this.parseMapLock) { - if (this.ScriptParseInfoMap.ContainsKey(uri)) + if (this.ScriptParseInfoMap.TryGetValue(uri, out ScriptParseInfo value)) { Logger.Verbose($"Found ScriptParseInfo for uri {uri}"); - return this.ScriptParseInfoMap[uri]; + return value; } else if (createIfNotExists) { diff --git a/src/Microsoft.SqlTools.ServiceLayer/Management/Common/DataContainer.cs b/src/Microsoft.SqlTools.ServiceLayer/Management/Common/DataContainer.cs index 7921d8e8..201d18ae 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Management/Common/DataContainer.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Management/Common/DataContainer.cs @@ -1191,7 +1191,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Management Server[@Name='{0}'] Database ", - connInfo.ConnectionDetails.ServerName.ToUpper(), + connInfo.ConnectionDetails.ServerName.ToUpper(CultureInfo.InvariantCulture), connInfo.ConnectionDetails.UserName); } else @@ -1205,7 +1205,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Management Server[@Name='{0}'] {2} ", - connInfo.ConnectionDetails.ServerName.ToUpper(), + connInfo.ConnectionDetails.ServerName.ToUpper(CultureInfo.InvariantCulture), connInfo.ConnectionDetails.UserName, connInfo.ConnectionDetails.DatabaseName); } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj b/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj index d17d55c1..b0ced717 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj +++ b/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj @@ -12,10 +12,10 @@ true true $(ToolsServiceTargetRuntimes) - - $(NoWarn);SYSLIB1045;CA1311;CA1854;CS8600;CS8603;CS8625 SqlTools Editor Services Host Protocol Library Provides message types and client/server APIs for the SqlTools Editor Services JSON protocol. + + $(NoWarn);CS8795 diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerSession.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerSession.cs index bad8ccee..e103f6ce 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerSession.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerSession.cs @@ -114,9 +114,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler if ((currentEvent.Name.Equals("sql_batch_completed") || currentEvent.Name.Equals("sql_batch_starting")) - && currentEvent.Values.ContainsKey("batch_text")) + && currentEvent.Values.TryGetValue("batch_text", out string value)) { - return currentEvent.Values["batch_text"].Contains("SELECT target_data FROM sys.dm_xe_session_targets") + return value.Contains("SELECT target_data FROM sys.dm_xe_session_targets") || currentEvent.Values["batch_text"].Contains("SELECT target_data FROM sys.dm_xe_database_session_targets"); } diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/SaveAsMarkdownFileStreamWriter.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/SaveAsMarkdownFileStreamWriter.cs index c3081f71..e5fc7743 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/SaveAsMarkdownFileStreamWriter.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/SaveAsMarkdownFileStreamWriter.cs @@ -19,10 +19,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// /// Writer for exporting results to a Markdown table. /// - public class SaveAsMarkdownFileStreamWriter : SaveAsStreamWriter + public partial class SaveAsMarkdownFileStreamWriter : SaveAsStreamWriter { private const string Delimiter = "|"; - private static readonly Regex NewlineRegex = new Regex(@"(\r\n|\n|\r)", RegexOptions.Compiled); + + [GeneratedRegex("(\\r\\n|\\n|\\r)", RegexOptions.Compiled)] + private static partial Regex GetNewLineRegex(); private readonly Encoding _encoding; private readonly string _lineSeparator; @@ -72,7 +74,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage this.WriteLine($"{Delimiter}{rowLine}{Delimiter}"); } - internal static string EncodeMarkdownField(string? field) + internal static string EncodeMarkdownField(string field) { // Special case for nulls if (field == null) @@ -89,7 +91,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage // @TODO: Allow option to encode multiple whitespace characters as   // Replace newlines with br tags, since cell values must be single line - field = NewlineRegex.Replace(field, @"
"); + field = GetNewLineRegex().Replace(field, @"
"); return field; } diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs index 0d0abd19..8f587d58 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs @@ -25,7 +25,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution /// Class that represents a resultset the was generated from a query. Contains logic for /// storing and retrieving results. Is contained by a Batch class. /// - public class ResultSet : IDisposable + public partial class ResultSet : IDisposable { #region Constants @@ -279,7 +279,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution // ReSharper disable once AccessToDisposedClosure The lambda is used immediately in string.Join call IEnumerable rowValues = fileOffsets.Select(rowOffset => fileStreamReader.ReadRow(rowOffset, 0, Columns)[0].DisplayValue); string singleString = string.Join(string.Empty, rowValues); - DbCellValue cellValue = new DbCellValue + var cellValue = new DbCellValue { DisplayValue = singleString, IsNull = false, @@ -369,7 +369,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution // Verify the request hasn't been cancelled cancellationToken.ThrowIfCancellationRequested(); - StorageDataReader dataReader = new StorageDataReader(dbDataReader); + var dataReader = new StorageDataReader(dbDataReader); // Open a writer for the file // @@ -514,7 +514,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution } // Create the new task - Task saveAsTask = new Task(async () => + var saveAsTask = new Task(async () => { try { @@ -638,7 +638,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution // sendResultsSemphore.Wait(); - ResultSet currentResultSetSnapshot = (ResultSet) MemberwiseClone(); + var currentResultSetSnapshot = (ResultSet) MemberwiseClone(); if (LastUpdatedSummary == null) // We need to send results available message. { // Fire off results Available task and await it @@ -739,13 +739,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution { if (Columns?.Length > 0 && RowCount != 0) { - Regex regex = new Regex(@"({.*?})"); var row = GetRow(0); for (int i = 0; i < Columns.Length; i++) { if (Columns[i].DataTypeName.Equals("nvarchar")) { - if (regex.IsMatch(row[i].DisplayValue)) + if (GetJsonRegex().IsMatch(row[i].DisplayValue)) { Columns[i].IsJson = true; } @@ -788,7 +787,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution // Returning false from .ReadAsync means there aren't any rows. // Create a storage data reader, read it, make sure there were results - StorageDataReader dataReader = new StorageDataReader(dbDataReader); + var dataReader = new StorageDataReader(dbDataReader); if (!await dataReader.ReadAsync(CancellationToken.None)) { throw new InvalidOperationException(SR.QueryServiceResultSetAddNoRows); @@ -804,6 +803,9 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution } } + [GeneratedRegex("({.*?})")] + private static partial Regex GetJsonRegex(); + #endregion } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs index f1de615f..ef8ec253 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs @@ -22,7 +22,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare /// /// Internal class for utilities shared between multiple schema compare operations /// - internal static class SchemaCompareUtils + internal static partial class SchemaCompareUtils { internal static DiffEntry CreateDiffEntry(SchemaDifference difference, DiffEntry parent) { @@ -31,7 +31,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare return null; } - DiffEntry diffEntry = new DiffEntry(); + var diffEntry = new DiffEntry(); diffEntry.UpdateAction = difference.UpdateAction; diffEntry.DifferenceType = difference.DifferenceType; diffEntry.Name = difference.Name; @@ -86,8 +86,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare { return null; } - ObjectIdentifier id = new ObjectIdentifier(sourceObj.NameParts); - SchemaComparisonExcludedObjectId excludedObjId = new SchemaComparisonExcludedObjectId(sourceObj.SqlObjectType, id); + var id = new ObjectIdentifier(sourceObj.NameParts); + var excludedObjId = new SchemaComparisonExcludedObjectId(sourceObj.SqlObjectType, id); return excludedObjId; } catch (ArgumentException) @@ -145,7 +145,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare // remove leading and trailing whitespace script = script.Trim(); // replace all multiple spaces with single space - script = Regex.Replace(script, " {2,}", " "); + script = GetScriptRegex().Replace(script, " "); } return script; } @@ -159,5 +159,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare } return script; } + + [GeneratedRegex(" {2,}")] + private static partial Regex GetScriptRegex(); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterCore.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterCore.cs index 46be8c9f..f6b80f91 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterCore.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScripterCore.cs @@ -189,7 +189,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting string tokenType = GetTokenTypeFromQuickInfo(quickInfoText, tokenText, caseSensitivity); if (tokenType != null) { - if (sqlObjectTypesFromQuickInfo.ContainsKey(tokenType.ToLowerInvariant())) + if (sqlObjectTypesFromQuickInfo.TryGetValue(tokenType.ToLowerInvariant(), out string sqlObjectType)) { // With SqlLogin authentication, the defaultSchema property throws an Exception when accessed. // This workaround ensures that a schema name is present by attempting @@ -203,8 +203,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting Location[] locations = GetSqlObjectDefinition( tokenText, schemaName, - sqlObjectTypesFromQuickInfo[tokenType.ToLowerInvariant()] - ); + sqlObjectType); DefinitionResult result = new DefinitionResult { IsErrorResult = this.error, @@ -232,7 +231,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting /// internal DefinitionResult GetDefinitionUsingDeclarationType(DeclarationType type, string databaseQualifiedName, string tokenText, string schemaName) { - if (sqlObjectTypes.ContainsKey(type)) + if (sqlObjectTypes.TryGetValue(type, out string sqlObjectType)) { // With SqlLogin authentication, the defaultSchema property throws an Exception when accessed. // This workaround ensures that a schema name is present by attempting @@ -246,8 +245,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting Location[] locations = GetSqlObjectDefinition( tokenText, schemaName, - sqlObjectTypes[type] - ); + sqlObjectType); DefinitionResult result = new DefinitionResult { IsErrorResult = this.error, @@ -288,7 +286,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting string[] lines = File.ReadAllLines(tempFileName); int lineCount = 0; string createSyntax = null; - if (objectScriptMap.ContainsKey(objectType.ToLower())) + if (objectScriptMap.ContainsKey(objectType.ToLower(System.Globalization.CultureInfo.InvariantCulture))) { createSyntax = string.Format("CREATE"); foreach (string line in lines) diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs index 677a1a5e..8739ae4e 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs @@ -102,7 +102,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting // Leaving the server name blank will automatically match whatever the server SMO is running against. StringBuilder urnBuilder = new StringBuilder(); - urnBuilder.AppendFormat("Server[@Name='{0}']/", server.ToUpper()); + urnBuilder.AppendFormat("Server[@Name='{0}']/", server.ToUpper(System.Globalization.CultureInfo.InvariantCulture)); urnBuilder.AppendFormat("Database[@Name='{0}']/", Urn.EscapeString(database)); bool hasParentObject = !string.IsNullOrWhiteSpace(scriptingObject.ParentName) diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/EnumUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/EnumUtils.cs index 2a7aeded..f567b9e3 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/EnumUtils.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/EnumUtils.cs @@ -38,9 +38,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public T GetValue(string displayName) { - if (this.Mapping.ContainsKey(displayName)) + if (this.Mapping.TryGetValue(displayName, out T value)) { - return this.Mapping[displayName]; + return value; } else { diff --git a/src/Microsoft.SqlTools.ServiceLayer/Utility/ResolvedFile.cs b/src/Microsoft.SqlTools.ServiceLayer/Utility/ResolvedFile.cs index a828593d..52623af3 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Utility/ResolvedFile.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Utility/ResolvedFile.cs @@ -38,7 +38,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility { get { - return ClientUri?.ToLower(); + return ClientUri?.ToLower(System.Globalization.CultureInfo.InvariantCulture); } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Utility/SqlScriptFormatters/FromSqlScript.cs b/src/Microsoft.SqlTools.ServiceLayer/Utility/SqlScriptFormatters/FromSqlScript.cs index f67d35d9..b2e26aaa 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Utility/SqlScriptFormatters/FromSqlScript.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Utility/SqlScriptFormatters/FromSqlScript.cs @@ -16,11 +16,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters /// /// Provides utilities for converting from SQL script syntax into POCOs. /// - public static class FromSqlScript + public static partial class FromSqlScript { // Regex: optionally starts with N, captures string wrapped in single quotes - private static readonly Regex StringRegex = new Regex("^N?'(.*)'$", RegexOptions.Compiled); - private static readonly Regex BracketRegex = new Regex(@"^\[(.*)\]$", RegexOptions.Compiled); + [GeneratedRegex("^N?'(.*)'$", RegexOptions.Compiled)] + private static partial Regex GetStringRegex(); + + [GeneratedRegex("^\\[(.*)\\]$", RegexOptions.Compiled)] + private static partial Regex GetBracketRegex(); /// /// Decodes a multipart identifier as used in a SQL script into an array of the multiple @@ -35,8 +38,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters /// public static string[] DecodeMultipartIdentifier(string multipartIdentifier) { - StringBuilder sb = new StringBuilder(); - List namedParts = new List(); + var sb = new StringBuilder(); + var namedParts = new List(); bool insideBrackets = false; bool bracketsClosed = false; for (int i = 0; i < multipartIdentifier.Length; i++) @@ -122,7 +125,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters literal = literal.Trim('(', ')'); // Attempt to unwrap inverted commas around a string - Match match = StringRegex.Match(literal); + Match match = GetStringRegex().Match(literal); if (match.Success) { // Like: N'stuff' or 'stuff' @@ -136,7 +139,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters /// /// Identifier to check. /// Boolean indicating if identifier is escaped with brackets. - public static bool IsIdentifierBracketed(string identifer) => BracketRegex.IsMatch(identifer); + public static bool IsIdentifierBracketed(string identifer) => GetBracketRegex().IsMatch(identifer); #region Private Helpers diff --git a/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/ScriptFile.cs b/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/ScriptFile.cs index c3b243ad..234a53a5 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/ScriptFile.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Workspace/Contracts/ScriptFile.cs @@ -27,7 +27,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts /// public string Id { - get { return this.ClientUri.ToLower(); } + get { return this.ClientUri.ToLower(System.Globalization.CultureInfo.InvariantCulture); } } /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/Workspace/Workspace.cs b/src/Microsoft.SqlTools.ServiceLayer/Workspace/Workspace.cs index 192605f0..c30def6c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Workspace/Workspace.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Workspace/Workspace.cs @@ -23,7 +23,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace /// Manages a "workspace" of script files that are open for a particular /// editing session. Also helps to navigate references between ScriptFiles. /// - public class Workspace : IDisposable + public partial class Workspace : IDisposable { #region Private Fields @@ -117,8 +117,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace } // This method allows FileNotFoundException to bubble up // if the file isn't found. - using (FileStream fileStream = new FileStream(resolvedFile.FilePath, FileMode.Open, FileAccess.Read)) - using (StreamReader streamReader = new StreamReader(fileStream, Encoding.UTF8)) + using (var fileStream = new FileStream(resolvedFile.FilePath, FileMode.Open, FileAccess.Read)) + using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { scriptFile = new ScriptFile(resolvedFile.FilePath, resolvedFile.ClientUri,streamReader); @@ -150,7 +150,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace // Client sent the path in URI format, extract the local path and trim // any extraneous slashes - Uri fileUri = new Uri(clientUri); + var fileUri = new Uri(clientUri); filePath = fileUri.LocalPath; if (filePath.StartsWith("//") || filePath.StartsWith("\\\\") || filePath.StartsWith("/")) { @@ -208,7 +208,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace return path; } - return Regex.Replace(path, @"`(?=[ \[\]])", ""); + return GetEscapeRegex().Replace(path, ""); } /// @@ -363,6 +363,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace { } + [GeneratedRegex("`(?=[ \\[\\]])")] + private static partial Regex GetEscapeRegex(); + #endregion } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/AzureFunctions/AzureFunctionsServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/AzureFunctions/AzureFunctionsServiceTests.cs index e573ff6b..dd2f9e2e 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/AzureFunctions/AzureFunctionsServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/AzureFunctions/AzureFunctionsServiceTests.cs @@ -15,7 +15,7 @@ using System.IO; namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.AzureFunctions { - class AzureFunctionsServiceTests + internal sealed class AzureFunctionsServiceTests { private string testAzureFunctionsFolder = Path.Combine("..", "..", "..", "AzureFunctions", "AzureFunctionTestFiles"); diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs index 52c2c27d..bde970aa 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs @@ -29,14 +29,14 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// public class ReliableConnectionTests { - internal class TestDataTransferErrorDetectionStrategy : DataTransferErrorDetectionStrategy + internal sealed class TestDataTransferErrorDetectionStrategy : DataTransferErrorDetectionStrategy { public bool InvokeCanRetrySqlException(SqlException exception) { return CanRetrySqlException(exception); } } - internal class TestSqlAzureTemporaryAndIgnorableErrorDetectionStrategy : SqlAzureTemporaryAndIgnorableErrorDetectionStrategy + internal sealed class TestSqlAzureTemporaryAndIgnorableErrorDetectionStrategy : SqlAzureTemporaryAndIgnorableErrorDetectionStrategy { public TestSqlAzureTemporaryAndIgnorableErrorDetectionStrategy() : base (new int[] { 100 }) @@ -54,7 +54,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection } } - internal class TestFixedDelayPolicy : FixedDelayPolicy + internal sealed class TestFixedDelayPolicy : FixedDelayPolicy { public TestFixedDelayPolicy( IErrorDetectionStrategy strategy, @@ -77,7 +77,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection } } - internal class TestProgressiveRetryPolicy : ProgressiveRetryPolicy + internal sealed class TestProgressiveRetryPolicy : ProgressiveRetryPolicy { public TestProgressiveRetryPolicy( IErrorDetectionStrategy strategy, @@ -97,7 +97,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection } } - internal class TestTimeBasedRetryPolicy : TimeBasedRetryPolicy + internal sealed class TestTimeBasedRetryPolicy : TimeBasedRetryPolicy { public TestTimeBasedRetryPolicy( IErrorDetectionStrategy strategy, @@ -916,7 +916,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection command.UpdatedRowSource = UpdateRowSource.None; Assert.AreEqual(UpdateRowSource.None, command.UpdatedRowSource); Assert.NotNull(command.GetUnderlyingCommand()); - Assert.Throws(() => command.ValidateConnectionIsSet()); + Assert.Throws(command.ValidateConnectionIsSet); command.Prepare(); Assert.NotNull(command.CreateParameter()); command.Cancel(); diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/BackupRestoreUrlTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/BackupRestoreUrlTests.cs index a8182c91..ed9229db 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/BackupRestoreUrlTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/BackupRestoreUrlTests.cs @@ -30,7 +30,7 @@ using static Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility.LiveConnec namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery { - class BackupRestoreUrlTests + internal sealed class BackupRestoreUrlTests { /// /// Create simple backup test diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/RestoreDatabaseServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/RestoreDatabaseServiceTests.cs index 6588b2f1..326eba9f 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/RestoreDatabaseServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/RestoreDatabaseServiceTests.cs @@ -574,7 +574,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery string backUpFilePath = string.Empty; if (backupFileNames != null) { - var filePaths = backupFileNames.Select(x => GetBackupFilePath(x)); + var filePaths = backupFileNames.Select(GetBackupFilePath); backUpFilePath = filePaths.Aggregate((current, next) => current + " ," + next); } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/LanguageServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/LanguageServiceTests.cs index a5b8ab63..9c8c5765 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/LanguageServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/LanguageServiceTests.cs @@ -368,7 +368,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer await langService.HandleDidChangeLanguageFlavorNotification(new LanguageFlavorChangeParams { Uri = scriptFile.ClientUri, - Language = LanguageService.SQL_LANG.ToLower(), + Language = LanguageService.SQL_LANG.ToLower(System.Globalization.CultureInfo.InvariantCulture), Flavor = "MSSQL" }, eventContextSql.Object); await langService.DelayedDiagnosticsTask; // to ensure completion and validation before moveing to next step @@ -379,7 +379,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer await langService.HandleDidChangeLanguageFlavorNotification(new LanguageFlavorChangeParams { Uri = scriptFile.ClientUri, - Language = LanguageService.SQL_CMD_LANG.ToLower(), + Language = LanguageService.SQL_CMD_LANG.ToLower(System.Globalization.CultureInfo.InvariantCulture), Flavor = "MSSQL" }, eventContextSqlCmd.Object); await langService.DelayedDiagnosticsTask; diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj index edb2fd7d..bbf770db 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj @@ -6,8 +6,6 @@ Microsoft.SqlTools.ServiceLayer.IntegrationTests true $(DefineConstants);TRACE - - $(NoWarn);SYSLIB1045;IDE0200;IDE0230;CA1311;CA1852;CA1854 diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectExplorer/ObjectExplorerServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectExplorer/ObjectExplorerServiceTests.cs index a8a68f3e..ab909240 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectExplorer/ObjectExplorerServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectExplorer/ObjectExplorerServiceTests.cs @@ -28,7 +28,7 @@ using static Microsoft.SqlTools.ServiceLayer.ObjectExplorer.ObjectExplorerServic namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer { - public class ObjectExplorerServiceTests + public partial class ObjectExplorerServiceTests { private ObjectExplorerService _service = TestServiceProvider.Instance.ObjectExplorerService; @@ -124,10 +124,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer { var query = ""; string databaseName = "#testDb#"; - await RunTest(databaseName, query, "TestDb", async (testDbName, session) => - { - await ExpandAndVerifyDatabaseNode(testDbName, session); - }); + await RunTest(databaseName, query, "TestDb", ExpandAndVerifyDatabaseNode); } [Test] @@ -376,7 +373,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer ConnectParams connectParams = TestServiceProvider.Instance.ConnectionProfileService.GetConnectionParameters(TestServerType.OnPrem, databaseName); //connectParams.Connection.Pooling = false; ConnectionDetails details = connectParams.Connection; - string uri = ObjectExplorerService.GenerateUri(details); + string uri = GenerateUri(details); var session = await _service.DoCreateSession(details, uri); Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "OE session created for database: {0}", databaseName)); @@ -387,10 +384,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer { Assert.That(session, Is.Not.Null, nameof(session)); Assert.That(session.Root, Is.Not.Null, nameof(session.Root)); - NodeInfo nodeInfo = session.Root.ToNodeInfo(); + var nodeInfo = session.Root.ToNodeInfo(); Assert.That(nodeInfo.IsLeaf, Is.False, "Should not be a leaf node"); - NodeInfo? databaseNode = null; + NodeInfo databaseNode = null; if (serverNode) { @@ -435,7 +432,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer { Assert.NotNull(session); Assert.NotNull(session.Root); - NodeInfo nodeInfo = session.Root.ToNodeInfo(); + var nodeInfo = session.Root.ToNodeInfo(); Assert.AreEqual(false, nodeInfo.IsLeaf); Assert.AreEqual(nodeInfo.NodeType, NodeTypes.Database.ToString()); Assert.True(nodeInfo.Label.Contains(databaseName)); @@ -457,7 +454,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer Console.WriteLine($"Session closed uri:{uri}"); } - private async Task ExpandTree(NodeInfo node, ObjectExplorerSession session, StringBuilder? stringBuilder = null, bool verifySystemObjects = false) + private async Task ExpandTree(NodeInfo node, ObjectExplorerSession session, StringBuilder stringBuilder = null, bool verifySystemObjects = false) { if (node != null && !node.IsLeaf) { @@ -552,7 +549,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer private async Task VerifyObjectExplorerTest(string databaseName, string testDbPrefix, string queryFileName, string baselineFileName, bool verifySystemObjects = false) { var query = string.IsNullOrEmpty(queryFileName) ? string.Empty : LoadScript(queryFileName); - StringBuilder stringBuilder = new StringBuilder(); + var stringBuilder = new StringBuilder(); await RunTest(databaseName, query, testDbPrefix, async (testDbName, session) => { await ExpandServerNodeAndVerifyDatabaseHierachy(testDbName, session, false); @@ -564,7 +561,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer // Dropped ledger objects have a randomly generated GUID appended to their name when they are deleted // For testing purposes, those guids need to be replaced with a deterministic string - actual = Regex.Replace(actual, "[A-Z0-9]{32}", "<>"); + actual = GetBaselineRegex().Replace(actual, "<>"); // Write output to a bin directory for easier comparison string assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty; @@ -640,5 +637,8 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer FileInfo inputFile = GetBaseLineFile(fileName); return TestUtilities.ReadTextAndNormalizeLineEndings(inputFile.FullName); } + + [GeneratedRegex("[A-Z0-9]{32}")] + private static partial Regex GetBaselineRegex(); } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/AutoParameterization/SqlParameterizerTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/AutoParameterization/SqlParameterizerTests.cs index 3c90a4ad..0300339a 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/AutoParameterization/SqlParameterizerTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/AutoParameterization/SqlParameterizerTests.cs @@ -113,7 +113,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.AutoParameterization // SQL greater than 300000 characters should throw string bigSql = string.Concat(Repeat(element: sqlLength_300, count: 1100)); DbCommand command2 = new SqlCommand { CommandText = bigSql }; - Assert.Throws(() => command2.Parameterize()); + Assert.Throws(command2.Parameterize); } /// @@ -128,7 +128,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.AutoParameterization string sql = string.Concat(Repeat(element: invalidSql, count: 1000)); DbCommand command = new SqlCommand { CommandText = sql }; - Assert.Throws(() => command.Parameterize()); + Assert.Throws(command.Parameterize); } /// @@ -149,7 +149,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.AutoParameterization GO"; DbCommand command = new SqlCommand { CommandText = sql }; - Assert.Throws(() => command.Parameterize()); + Assert.Throws(command.Parameterize); } /// diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/SharedAccessSignatureCreatorTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/SharedAccessSignatureCreatorTests.cs index 8aca355a..f9d8fc84 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/SharedAccessSignatureCreatorTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/SharedAccessSignatureCreatorTests.cs @@ -15,7 +15,7 @@ using Azure.Storage.Sas; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery { - class SharedAccessSignatureCreatorTests + internal sealed class SharedAccessSignatureCreatorTests { [Test] public void GetServiceSasUriForContainerReturnsNullWhenCannotGenerateSasUri() diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/CellUpdateTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/CellUpdateTests.cs index bce1ab60..be65f921 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/CellUpdateTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/CellUpdateTests.cs @@ -105,8 +105,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData yield return new object[] {"0x000", new byte[] {0x00, 0x00}, "0x0000"}; // Base16, odd // Single byte tests - yield return new object[] {"50", new byte[] {0x32}, "0x32"}; // Base10 - yield return new object[] {"050", new byte[] {0x32}, "0x32"}; // Base10, leading zeros + yield return new object[] {"50", "2"u8.ToArray(), "0x32"}; // Base10 + yield return new object[] {"050", "2"u8.ToArray(), "0x32"}; // Base10, leading zeros yield return new object[] {"0xF0", new byte[] {0xF0}, "0xF0"}; // Base16 yield return new object[] {"0x0F", new byte[] {0x0F}, "0x0F"}; // Base16, leading zeros yield return new object[] {"0xF", new byte[] {0x0F}, "0x0F"}; // Base16, odd @@ -296,7 +296,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData return new DbColumnWrapper(new CellUpdateTestDbColumn(typeof(T), dataTypeName, allowNull, colSize)); } - private class CellUpdateTestDbColumn : DbColumn + private sealed class CellUpdateTestDbColumn : DbColumn { public CellUpdateTestDbColumn(Type dataType, string dataTypeName, bool allowNull = true, int? colSize = null) { diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowCreateTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowCreateTests.cs index 956d8ea7..438338f5 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowCreateTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowCreateTests.cs @@ -21,18 +21,18 @@ using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { - public class RowCreateTests + public partial class RowCreateTests { [Test] public async Task RowCreateConstruction() { // Setup: Create the values to store const long rowId = 100; - Common.TestDbColumnsWithTableMetadata data = new Common.TestDbColumnsWithTableMetadata(false, false, 0, 0); + var data = new Common.TestDbColumnsWithTableMetadata(false, false, 0, 0); ResultSet rs = await Common.GetResultSet(data.DbColumns, false); // If: I create a RowCreate instance - RowCreate rc = new RowCreate(rowId, rs, data.TableMetadata); + var rc = new RowCreate(rowId, rs, data.TableMetadata); // Then: The values I provided should be available Assert.AreEqual(rowId, rc.RowId); @@ -67,7 +67,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // Setup: Generate the parameters for the row create var data = new Common.TestDbColumnsWithTableMetadata(false, includeIdentity, defaultCols, nullableCols); var rs = await Common.GetResultSet(data.DbColumns, includeIdentity); - RowCreate rc = new RowCreate(100, rs, data.TableMetadata); + var rc = new RowCreate(100, rs, data.TableMetadata); // If: I ask for a script to be generated without setting any values // Then: An exception should be thrown for missing cells @@ -116,11 +116,11 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Generate the parameters for the row create - Common.TestDbColumnsWithTableMetadata data = new Common.TestDbColumnsWithTableMetadata(false, includeIdentity, colsWithDefaultConstraints, colsThatAllowNull); + var data = new Common.TestDbColumnsWithTableMetadata(false, includeIdentity, colsWithDefaultConstraints, colsThatAllowNull); ResultSet rs = await Common.GetResultSet(data.DbColumns, includeIdentity); // ... Create a row create and set the appropriate number of cells - RowCreate rc = new RowCreate(100, rs, data.TableMetadata); + var rc = new RowCreate(100, rs, data.TableMetadata); Common.AddCells(rc, valuesToSkipSetting); // If: I ask for the script for the row insert @@ -139,8 +139,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData if (expectedOutput == null) { // If expected output was null make sure we match the default values reges - Regex r = new Regex(@"INSERT INTO (.+) DEFAULT VALUES"); - Match m = r.Match(sql); + Match m = GetInsert1Regex().Match(sql); Assert.True(m.Success); // Table name matches @@ -149,8 +148,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData else { // Do the whole validation - Regex r = new Regex(@"INSERT INTO (.+)\((.+)\) VALUES \((.+)\)"); - Match m = r.Match(sql); + Match m = GetInsert2Regex().Match(sql); Assert.True(m.Success); // Table name matches @@ -174,14 +172,14 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // Setup: // ... Generate the parameters for the row create const long rowId = 100; - Common.TestDbColumnsWithTableMetadata data = new Common.TestDbColumnsWithTableMetadata(false, includeIdentity, 0, 0); + var data = new Common.TestDbColumnsWithTableMetadata(false, includeIdentity, 0, 0); ResultSet rs = await Common.GetResultSet(data.DbColumns, includeIdentity); // ... Setup a db reader for the result of an insert var newRowReader = Common.GetNewRowDataReader(data.DbColumns, includeIdentity); // If: I ask for the change to be applied - RowCreate rc = new RowCreate(rowId, rs, data.TableMetadata); + var rc = new RowCreate(rowId, rs, data.TableMetadata); await rc.ApplyChanges(newRowReader); // Then: The result set should have an additional row in it @@ -226,9 +224,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Generate the row create object - Common.TestDbColumnsWithTableMetadata data = new Common.TestDbColumnsWithTableMetadata(false, includeIdentity, defaultCols, nullableCols); + var data = new Common.TestDbColumnsWithTableMetadata(false, includeIdentity, defaultCols, nullableCols); ResultSet rs = await Common.GetResultSet(data.DbColumns, includeIdentity); - RowCreate rc = new RowCreate(100, rs, data.TableMetadata); + var rc = new RowCreate(100, rs, data.TableMetadata); // ... Create a mock db connection for building the command var mockConn = new TestSqlConnection(); @@ -280,14 +278,14 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Generate the parameters for the row create - Common.TestDbColumnsWithTableMetadata data = new Common.TestDbColumnsWithTableMetadata(false, includeIdentity, defaultCols, nullableCols); + var data = new Common.TestDbColumnsWithTableMetadata(false, includeIdentity, defaultCols, nullableCols); ResultSet rs = await Common.GetResultSet(data.DbColumns, includeIdentity); // ... Mock db connection for building the command var mockConn = new TestSqlConnection(null); // ... Create a row create and set the appropriate number of cells - RowCreate rc = new RowCreate(100, rs, data.TableMetadata); + var rc = new RowCreate(100, rs, data.TableMetadata); Common.AddCells(rc, valuesToSkip); // If: I ask for the command for the row insert @@ -311,8 +309,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData Assert.AreEqual(3, splitSql.Length); // Check the declare statement first - Regex declareRegex = new Regex(@"^DECLARE @(.+) TABLE \((.+)\)$"); - Match declareMatch = declareRegex.Match(splitSql[0]); + Match declareMatch = GetDeclareRegex().Match(splitSql[0]); Assert.True(declareMatch.Success); // Declared table name matches @@ -327,7 +324,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData if (expectedOutput.ExpectedInColumns == 0 || expectedOutput.ExpectedInValues == 0) { // If expected output was null make sure we match the default values reges - Regex insertRegex = new Regex(@"^INSERT INTO (.+) OUTPUT (.+) INTO @(.+) DEFAULT VALUES$"); + var insertRegex = GetInsertRegex(); Match insertMatch = insertRegex.Match(splitSql[1]); Assert.True(insertMatch.Success); @@ -347,7 +344,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData else { // Do the whole validation - Regex insertRegex = new Regex(@"^INSERT INTO (.+)\((.+)\) OUTPUT (.+) INTO @(.+) VALUES \((.+)\)$"); + var insertRegex = GetInsertFullRegex(); Match insertMatch = insertRegex.Match(splitSql[1]); Assert.True(insertMatch.Success); @@ -380,7 +377,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData } // Check the select statement last - Regex selectRegex = new Regex(@"^SELECT (.+) FROM @(.+)$"); + var selectRegex = GetSelectRegex(); Match selectMatch = selectRegex.Match(splitSql[2]); Assert.True(selectMatch.Success); @@ -425,9 +422,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: Generate a row create with default values const long rowId = 100; - Common.TestDbColumnsWithTableMetadata data = new Common.TestDbColumnsWithTableMetadata(false, false, 3, 0); + var data = new Common.TestDbColumnsWithTableMetadata(false, false, 3, 0); ResultSet rs = await Common.GetResultSet(data.DbColumns, false); - RowCreate rc = new RowCreate(rowId, rs, data.TableMetadata); + var rc = new RowCreate(rowId, rs, data.TableMetadata); // If: I request an edit row from the row create EditRow er = rc.GetEditRow(null); @@ -451,9 +448,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: Generate a row create with an identity column const long rowId = 100; - Common.TestDbColumnsWithTableMetadata data = new Common.TestDbColumnsWithTableMetadata(false, true, 0, 0); + var data = new Common.TestDbColumnsWithTableMetadata(false, true, 0, 0); ResultSet rs = await Common.GetResultSet(data.DbColumns, true); - RowCreate rc = new RowCreate(rowId, rs, data.TableMetadata); + var rc = new RowCreate(rowId, rs, data.TableMetadata); // If: I request an edit row from the row created EditRow er = rc.GetEditRow(null); @@ -573,7 +570,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData var etm = Common.GetCustomEditTableMetadata(cols); // ... Create the row create - RowCreate rc = new RowCreate(100, rs, etm); + var rc = new RowCreate(100, rs, etm); // If: I set a cell in the newly created row to something that will be corrected EditUpdateCellResult eucr = rc.SetCell(0, "1000"); @@ -644,9 +641,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Generate the parameters for the row create - Common.TestDbColumnsWithTableMetadata data = new Common.TestDbColumnsWithTableMetadata(false, false, defaultCols, 0); + var data = new Common.TestDbColumnsWithTableMetadata(false, false, defaultCols, 0); ResultSet rs = await Common.GetResultSet(data.DbColumns, false); - RowCreate rc = new RowCreate(100, rs, data.TableMetadata); + var rc = new RowCreate(100, rs, data.TableMetadata); // If: I attempt to revert a cell that has not been set EditRevertCellResult result = rc.RevertCell(0); @@ -673,9 +670,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Generate the parameters for the row create - Common.TestDbColumnsWithTableMetadata data = new Common.TestDbColumnsWithTableMetadata(false, false, defaultCols, 0); + var data = new Common.TestDbColumnsWithTableMetadata(false, false, defaultCols, 0); ResultSet rs = await Common.GetResultSet(data.DbColumns, false); - RowCreate rc = new RowCreate(100, rs, data.TableMetadata); + var rc = new RowCreate(100, rs, data.TableMetadata); rc.SetCell(0, "1"); // If: I attempt to revert a cell that was set @@ -720,5 +717,25 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData public int ExpectedInValues { get; } public int ExpectedOutColumns { get; } } + + #region Generated Regex + [GeneratedRegex("INSERT INTO (.+) DEFAULT VALUES")] + private static partial Regex GetInsert1Regex(); + + [GeneratedRegex("INSERT INTO (.+)\\((.+)\\) VALUES \\((.+)\\)")] + private static partial Regex GetInsert2Regex(); + + [GeneratedRegex("^DECLARE @(.+) TABLE \\((.+)\\)$")] + private static partial Regex GetDeclareRegex(); + + [GeneratedRegex("^INSERT INTO (.+) OUTPUT (.+) INTO @(.+) DEFAULT VALUES$")] + private static partial Regex GetInsertRegex(); + + [GeneratedRegex("^INSERT INTO (.+)\\((.+)\\) OUTPUT (.+) INTO @(.+) VALUES \\((.+)\\)$")] + private static partial Regex GetInsertFullRegex(); + + [GeneratedRegex("^SELECT (.+) FROM @(.+)$")] + private static partial Regex GetSelectRegex(); + #endregion } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowEditBaseTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowEditBaseTests.cs index 3d9f6f63..953890dd 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowEditBaseTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowEditBaseTests.cs @@ -251,7 +251,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData return resultSet; } - private class RowEditTester : RowEditBase + private sealed class RowEditTester : RowEditBase { public RowEditTester(ResultSet rs, EditTableMetadata meta) : base(0, rs, meta) { } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowUpdateTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowUpdateTests.cs index fb5b90d0..e359c31d 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowUpdateTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowUpdateTests.cs @@ -21,7 +21,7 @@ using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { - public class RowUpdateTests + public partial class RowUpdateTests { [Test] public async Task RowUpdateConstruction() @@ -32,7 +32,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData var rs = await Common.GetResultSet(data.DbColumns, false); // If: I create a RowUpdate instance - RowUpdate rc = new RowUpdate(rowId, rs, data.TableMetadata); + var rc = new RowUpdate(rowId, rs, data.TableMetadata); // Then: The values I provided should be available Assert.AreEqual(rowId, rc.RowId); @@ -61,7 +61,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // If: // ... I add updates to all the cells in the row - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); Common.AddCells(ru, 1); // ... Then I update a cell back to it's old value @@ -83,8 +83,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData Assert.True(eucr.IsRowDirty); // ... It should be formatted as an update script - Regex r = new Regex(@"UPDATE .+ SET (.*) WHERE"); - var m = r.Match(ru.GetScript()); + var m = GetUpdateRegex().Match(ru.GetScript()); // ... It should have 2 updates string updates = m.Groups[1].Value; @@ -102,7 +101,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // If: // ... I add updates to one cell in the row - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); ru.SetCell(1, "qqq"); // ... Then I update the cell to its original value @@ -149,7 +148,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData var etm = Common.GetCustomEditTableMetadata(cols); // ... Create the row update - RowUpdate ru = new RowUpdate(0, rs, etm); + var ru = new RowUpdate(0, rs, etm); // If: I set a cell in the newly created row to something that will be corrected EditUpdateCellResult eucr = ru.SetCell(0, "1000"); @@ -214,7 +213,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData ResultSet rs = await Common.GetResultSet(data.DbColumns, true); // If: I ask for a script to be generated for update - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); Common.AddCells(ru, 1); string script = ru.GetScript(); @@ -226,7 +225,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData string regexString = isMemoryOptimized ? @"UPDATE (.+) WITH \(SNAPSHOT\) SET (.*) WHERE .+" : @"UPDATE (.+) SET (.*) WHERE .+"; - Regex r = new Regex(regexString); + var r = new Regex(regexString); var m = r.Match(script); Assert.True(m.Success); @@ -248,7 +247,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // ... Create a row update with cell updates var data = new Common.TestDbColumnsWithTableMetadata(isMemoryOptimized, includeIdentity, 0, 0); var rs = await Common.GetResultSet(data.DbColumns, includeIdentity); - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); Common.AddCells(ru, includeIdentity ? 1 : 0); // ... Mock db connection for building the command @@ -267,8 +266,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData Assert.True(splitSql.Length >= 3); // Check the declare statement first - Regex declareRegex = new Regex(@"^DECLARE @(.+) TABLE \((.+)\)$"); - Match declareMatch = declareRegex.Match(splitSql[0]); + Match declareMatch = GetDeclareTableRegex().Match(splitSql[0]); Assert.True(declareMatch.Success); // Declared table name matches @@ -283,7 +281,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData string regex = isMemoryOptimized ? @"^UPDATE (.+) WITH \(SNAPSHOT\) SET (.+) OUTPUT (.+) INTO @(.+) WHERE .+$" : @"^UPDATE (.+) SET (.+) OUTPUT (.+) INTO @(.+) WHERE .+$"; - Regex updateRegex = new Regex(regex); + var updateRegex = new Regex(regex); Match updateMatch = updateRegex.Match(splitSql[10]); Assert.True(updateMatch.Success); @@ -304,8 +302,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData Assert.That(updateMatch.Groups[4].Value, Does.EndWith("Output")); // Check the select statement last - Regex selectRegex = new Regex(@"^SELECT (.+) FROM @(.+)$"); - Match selectMatch = selectRegex.Match(splitSql[11]); + Match selectMatch = GetSelectRegex().Match(splitSql[11]); Assert.True(selectMatch.Success); // Correct number of columns in select statement @@ -343,7 +340,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // Setup: Create a row update with a cell set var data = new Common.TestDbColumnsWithTableMetadata(false, false, 0, 0); var rs = await Common.GetResultSet(data.DbColumns, false); - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); ru.SetCell(0, "foo"); // If: I attempt to get an edit row @@ -399,7 +396,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // ... Create a row update (no cell updates needed) var data = new Common.TestDbColumnsWithTableMetadata(false, includeIdentity, 0, 0); var rs = await Common.GetResultSet(data.DbColumns, includeIdentity); - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); long oldBytesWritten = rs.totalBytesWritten; // ... Setup a db reader for the result of an update @@ -421,7 +418,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // ... Create a row update (no cell updates needed) var data = new Common.TestDbColumnsWithTableMetadata(false, true, 0, 0); var rs = await Common.GetResultSet(data.DbColumns, true); - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); // If: I ask for the changes to be applied with a null db reader // Then: I should get an exception @@ -439,7 +436,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // ... Create a row update (no cell updates needed) var data = new Common.TestDbColumnsWithTableMetadata(false, false, 0, 0); var rs = await Common.GetResultSet(data.DbColumns, false); - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); // If: I attempt to revert a cell that is out of range // Then: I should get an exception @@ -453,7 +450,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // ... Create a row update (no cell updates needed) var data = new Common.TestDbColumnsWithTableMetadata(false, true, 0, 0); var rs = await Common.GetResultSet(data.DbColumns, true); - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); // If: I attempt to revert a cell that has not been set EditRevertCellResult result = ru.RevertCell(0); @@ -480,7 +477,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // ... Create a row update var data = new Common.TestDbColumnsWithTableMetadata(false, false, 0, 0); var rs = await Common.GetResultSet(data.DbColumns, false); - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); ru.SetCell(0, "qqq"); ru.SetCell(1, "qqq"); @@ -509,7 +506,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // ... Create a row update var data = new Common.TestDbColumnsWithTableMetadata(false, false, 0, 0); var rs = await Common.GetResultSet(data.DbColumns, false); - RowUpdate ru = new RowUpdate(0, rs, data.TableMetadata); + var ru = new RowUpdate(0, rs, data.TableMetadata); ru.SetCell(0, "qqq"); // If: I attempt to revert a cell that was set @@ -538,5 +535,14 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData var rs = await Common.GetResultSet(data.DbColumns, false); return new RowUpdate(0, rs, data.TableMetadata); } + + [GeneratedRegex("^DECLARE @(.+) TABLE \\((.+)\\)$")] + private static partial Regex GetDeclareTableRegex(); + + [GeneratedRegex("^SELECT (.+) FROM @(.+)$")] + private static partial Regex GetSelectRegex(); + + [GeneratedRegex("UPDATE .+ SET (.*) WHERE")] + private static partial Regex GetUpdateRegex(); } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/SessionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/SessionTests.cs index 40e878b4..b979a0e7 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/SessionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/SessionTests.cs @@ -26,7 +26,7 @@ using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { - public class SessionTests + public partial class SessionTests { #region Construction Tests @@ -42,8 +42,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData public void SessionConstructionValid() { // If: I create a session object with a proper arguments - Mock mockFactory = new Mock(); - EditSession s = new EditSession(mockFactory.Object); + var mockFactory = new Mock(); + var s = new EditSession(mockFactory.Object); // Then: // ... The edit cache should not exist @@ -87,7 +87,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData ConnectionService.Instance.OwnerToConnectionMap[ci.OwnerUri] = ci; var fsf = MemoryFileSystem.GetFileStreamFactory(); - Query query = new Query(Constants.StandardQuery, ci, new QueryExecutionSettings(), fsf); + var query = new Query(Constants.StandardQuery, ci, new QueryExecutionSettings(), fsf); query.Execute(); query.ExecutionTask.Wait(); @@ -116,8 +116,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session without initializing - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object); + var emf = new Mock(); + var s = new EditSession(emf.Object); // If: I ask to create a row without initializing // Then: I should get an exception @@ -292,8 +292,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session and fake that it has been initialized - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object) {IsInitialized = true}; + var emf = new Mock(); + var s = new EditSession(emf.Object) {IsInitialized = true}; // If: I initialize it // Then: I should get an exception @@ -305,8 +305,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session and fake that it is in progress of initializing - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object) {InitializeTask = new Task(() => {})}; + var emf = new Mock(); + var s = new EditSession(emf.Object) {InitializeTask = new Task(() => {})}; // If: I initialize it // Then: I should get an exception @@ -320,8 +320,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session that hasn't been initialized - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object); + var emf = new Mock(); + var s = new EditSession(emf.Object); Assert.Catch(() => s.Initialize(initParams, c, qr, sh, fh), "I initialize it with a missing parameter. It should throw an exception"); } @@ -381,12 +381,12 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a metadata factory that throws - Mock emf = new Mock(); + var emf = new Mock(); emf.Setup(f => f.GetObjectMetadata(It.IsAny(), It.IsAny(), It.IsAny())) .Throws(); // ... Create a session that hasn't been initialized - EditSession s = new EditSession(emf.Object); + var s = new EditSession(emf.Object); // ... Create a mock for verifying the failure handler will be called var successHandler = DoNothingSuccessMock; @@ -414,15 +414,15 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // ... Create a metadata factory that will return some generic column information var b = QueryExecution.Common.GetBasicExecutedBatch(); var etm = Common.GetCustomEditTableMetadata(b.ResultSets[0].Columns.Cast().ToArray()); - Mock emf = new Mock(); + var emf = new Mock(); emf.Setup(f => f.GetObjectMetadata(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(etm); // ... Create a session that hasn't been initialized - EditSession s = new EditSession(emf.Object); + var s = new EditSession(emf.Object); // ... Create a query runner that will fail via exception - Mock qr = new Mock(); + var qr = new Mock(); qr.Setup(r => r(It.IsAny())).Throws(new Exception("qqq")); // ... Create a mock for verifying the failure handler will be called @@ -451,15 +451,15 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // ... Create a metadata factory that will return some generic column information var b = QueryExecution.Common.GetBasicExecutedBatch(); var etm = Common.GetCustomEditTableMetadata(b.ResultSets[0].Columns.Cast().ToArray()); - Mock emf = new Mock(); + var emf = new Mock(); emf.Setup(f => f.GetObjectMetadata(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(etm); // ... Create a session that hasn't been initialized - EditSession s = new EditSession(emf.Object); + var s = new EditSession(emf.Object); // ... Create a query runner that will fail via returning a null query - Mock qr = new Mock(); + var qr = new Mock(); qr.Setup(r => r(It.IsAny())) .Returns(Task.FromResult(new EditSession.EditSessionQueryExecutionState(null, message))); @@ -490,15 +490,15 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData var q = QueryExecution.Common.GetBasicExecutedQuery(); var rs = q.Batches[0].ResultSets[0]; var etm = Common.GetCustomEditTableMetadata(rs.Columns.Cast().ToArray()); - Mock emf = new Mock(); + var emf = new Mock(); emf.Setup(f => f.GetObjectMetadata(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(etm); // ... Create a session that hasn't been initialized - EditSession s = new EditSession(emf.Object); + var s = new EditSession(emf.Object); // ... Create a query runner that will return a successful query - Mock qr = new Mock(); + var qr = new Mock(); qr.Setup(r => r(It.IsAny())) .Returns(Task.FromResult(new EditSession.EditSessionQueryExecutionState(q))); @@ -533,8 +533,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session without initializing - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object); + var emf = new Mock(); + var s = new EditSession(emf.Object); // If: I ask to delete a row without initializing // Then: I should get an exception @@ -583,8 +583,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session without initializing - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object); + var emf = new Mock(); + var s = new EditSession(emf.Object); // If: I ask to revert a row without initializing // Then: I should get an exception @@ -683,8 +683,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session without initializing - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object); + var emf = new Mock(); + var s = new EditSession(emf.Object); // If: I ask to revert a cell without initializing // Then: I should get an exception @@ -724,8 +724,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session without initializing - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object); + var emf = new Mock(); + var s = new EditSession(emf.Object); // If: I ask to update a cell without initializing // Then: I should get an exception @@ -807,8 +807,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session without initializing - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object); + var emf = new Mock(); + var s = new EditSession(emf.Object); // If: I ask to update a cell without initializing // Then: I should get an exception @@ -974,8 +974,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session without initializing - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object); + var emf = new Mock(); + var s = new EditSession(emf.Object); // If: I ask to script edits without initializing // Then: I should get an exception @@ -1001,12 +1001,12 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData EditSession s = await GetBasicSession(); // ... Add two mock edits that will generate a script - Mock edit = new Mock(); + var edit = new Mock(); edit.Setup(e => e.GetScript()).Returns("test"); s.EditCache[0] = edit.Object; s.EditCache[1] = edit.Object; - using (SelfCleaningTempFile file = new SelfCleaningTempFile()) + using (var file = new SelfCleaningTempFile()) { // If: I script the edit cache to a local output path string outputPath = s.ScriptEdits(file.FilePath); @@ -1029,8 +1029,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { // Setup: // ... Create a session without initializing - Mock emf = new Mock(); - EditSession s = new EditSession(emf.Object); + var emf = new Mock(); + var s = new EditSession(emf.Object); // If: I ask to script edits without initializing // Then: I should get an exception @@ -1088,7 +1088,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData DbConnection conn = new TestSqlConnection(null); // ... Mock a task that has not completed - Task notCompleted = new Task(() => {}); + var notCompleted = new Task(() => {}); s.CommitTask = notCompleted; // If: I attempt to commit while a task is in progress @@ -1106,7 +1106,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData DbConnection conn = new TestSqlConnection(null); // ... Add a mock commands for fun - Mock edit = new Mock(); + var edit = new Mock(); edit.Setup(e => e.GetCommand(It.IsAny())).Returns(dbc => dbc.CreateCommand()); edit.Setup(e => e.ApplyChanges(It.IsAny())).Returns(Task.FromResult(0)); s.EditCache[0] = edit.Object; @@ -1150,7 +1150,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData DbConnection conn = new TestSqlConnection(null); // ... Add a mock edit that will explode on generating a command - Mock edit = new Mock(); + var edit = new Mock(); edit.Setup(e => e.GetCommand(It.IsAny())).Throws(); s.EditCache[0] = edit.Object; @@ -1194,7 +1194,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData var data = new Common.TestDbColumnsWithTableMetadata(false, false, 0, 0); // If: I generate a query for selecting rows without a limit - EditInitializeFiltering eif = new EditInitializeFiltering + var eif = new EditInitializeFiltering { LimitResults = null }; @@ -1202,7 +1202,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // Then: // ... The query should look like a select statement - Regex selectRegex = new Regex("SELECT (.+) FROM (.+)", RegexOptions.IgnoreCase); + Regex selectRegex = GetSelectRegex(); var match = selectRegex.Match(query); Assert.True(match.Success); @@ -1223,7 +1223,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // If: I generate a query for selecting rows with a negative limit // Then: An exception should be thrown - EditInitializeFiltering eif = new EditInitializeFiltering + var eif = new EditInitializeFiltering { LimitResults = -1 }; @@ -1237,7 +1237,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData var data = new Common.TestDbColumnsWithTableMetadata(false, false, 0, 0); // If: I generate a query for selecting rows without a limit - EditInitializeFiltering eif = new EditInitializeFiltering + var eif = new EditInitializeFiltering { LimitResults = limit }; @@ -1245,7 +1245,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // Then: // ... The query should look like a select statement - Regex selectRegex = new Regex(@"SELECT TOP (\d+) (.+) FROM (.+)", RegexOptions.IgnoreCase); + var selectRegex = GetSelectTopRegex(); var match = selectRegex.Match(query); Assert.True(match.Success); @@ -1286,7 +1286,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData private static Mock> DoNothingSuccessMock { get { - Mock> successHandler = new Mock>(); + var successHandler = new Mock>(); successHandler.Setup(f => f()).Returns(Task.FromResult(0)); return successHandler; } @@ -1296,7 +1296,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { get { - Mock> failureHandler = new Mock>(); + var failureHandler = new Mock>(); failureHandler.Setup(f => f(It.IsAny())).Returns(Task.FromResult(0)); return failureHandler; } @@ -1309,5 +1309,11 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData EditTableMetadata etm = Common.GetCustomEditTableMetadata(rs.Columns.Cast().ToArray()); return await Common.GetCustomSession(q, etm); } + + [GeneratedRegex("SELECT (.+) FROM (.+)", RegexOptions.IgnoreCase)] + private static partial Regex GetSelectRegex(); + + [GeneratedRegex("SELECT TOP (\\d+) (.+) FROM (.+)", RegexOptions.IgnoreCase)] + private static partial Regex GetSelectTopRegex(); } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/AutocompleteTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/AutocompleteTests.cs index ad158a64..d4242c45 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/AutocompleteTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/AutocompleteTests.cs @@ -70,7 +70,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer await langService.HandleDidChangeLanguageFlavorNotification(new LanguageFlavorChangeParams { Uri = textDocument.TextDocument.Uri, - Language = LanguageService.SQL_LANG.ToLower(), + Language = LanguageService.SQL_LANG.ToLower(System.Globalization.CultureInfo.InvariantCulture), Flavor = "NotMSSQL" }, null); await langService.HandleSignatureHelpRequest(textDocument, signatureRequestContext.Object); diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/LanguageServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/LanguageServiceTests.cs index 220469c7..ce93f17c 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/LanguageServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/LanguageServer/LanguageServiceTests.cs @@ -152,7 +152,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer Assert.AreEqual(0, AutoCompleteHelper.EmptyCompletionList.Length); } - internal class TestScriptDocumentInfo : ScriptDocumentInfo + internal sealed class TestScriptDocumentInfo : ScriptDocumentInfo { public TestScriptDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile, ScriptParseInfo scriptParseInfo, string tokenText = null) diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Messaging/MessageReaderTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Messaging/MessageReaderTests.cs index a7a729aa..dff70fda 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Messaging/MessageReaderTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Messaging/MessageReaderTests.cs @@ -95,7 +95,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging inputStream.Flush(); inputStream.Seek(0, SeekOrigin.Begin); - Assert.ThrowsAsync(() => messageReader.ReadMessage(), "An exception should be thrown while reading"); + Assert.ThrowsAsync(messageReader.ReadMessage, "An exception should be thrown while reading"); } } @@ -113,7 +113,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging inputStream.Flush(); inputStream.Seek(0, SeekOrigin.Begin); - Assert.ThrowsAsync(() => messageReader.ReadMessage(), "An exception should be thrown while reading") ; + Assert.ThrowsAsync(messageReader.ReadMessage, "An exception should be thrown while reading") ; } } @@ -131,7 +131,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging inputStream.Flush(); inputStream.Seek(0, SeekOrigin.Begin); - Assert.ThrowsAsync(() => messageReader.ReadMessage(), "An exception should be thrown while reading"); + Assert.ThrowsAsync(messageReader.ReadMessage, "An exception should be thrown while reading"); } } @@ -153,9 +153,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging inputStream.Flush(); inputStream.Seek(0, SeekOrigin.Begin); - Assert.ThrowsAsync(() => messageReader.ReadMessage(), "The first read should fail with an exception while deserializing"); + Assert.ThrowsAsync(messageReader.ReadMessage, "The first read should fail with an exception while deserializing"); - Assert.ThrowsAsync(() => messageReader.ReadMessage(), "The second read should fail with an exception while reading headers"); + Assert.ThrowsAsync(messageReader.ReadMessage, "The second read should fail with an exception while reading headers"); } } @@ -176,7 +176,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging inputStream.Flush(); inputStream.Seek(0, SeekOrigin.Begin); - Assert.ThrowsAsync(() => messageReader.ReadMessage(), "An exception should be thrown while reading the first one"); + Assert.ThrowsAsync(messageReader.ReadMessage, "An exception should be thrown while reading the first one"); // ... A test event should be successfully read from the second one Message messageResult = messageReader.ReadMessage().Result; diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Messaging/TestMessageTypes.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Messaging/TestMessageTypes.cs index 1253d288..cbd4c799 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Messaging/TestMessageTypes.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Messaging/TestMessageTypes.cs @@ -12,7 +12,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging { #region Request Types - internal class TestRequest + internal sealed class TestRequest { public Task ProcessMessage(MessageWriter messageWriter) { @@ -20,7 +20,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging } } - internal class TestRequestArguments + internal sealed class TestRequestArguments { public string SomeString { get; set; } } @@ -29,11 +29,11 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging #region Response Types - internal class TestResponse + internal sealed class TestResponse { } - internal class TestResponseBody + internal sealed class TestResponseBody { public string SomeString { get; set; } } @@ -42,11 +42,11 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging #region Event Types - internal class TestEvent + internal sealed class TestEvent { } - internal class TestEventBody + internal sealed class TestEventBody { public string SomeString { get; set; } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Microsoft.SqlTools.ServiceLayer.UnitTests.csproj b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Microsoft.SqlTools.ServiceLayer.UnitTests.csproj index 0f947ee0..1ae7855c 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Microsoft.SqlTools.ServiceLayer.UnitTests.csproj +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Microsoft.SqlTools.ServiceLayer.UnitTests.csproj @@ -6,8 +6,8 @@ false - - $(NoWarn);SYSLIB1045;IDE0200;IDE0230;CA1311;CA1852;CA1854 + + $(NoWarn);CS8795 diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/GroupBySchemaTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/GroupBySchemaTests.cs index dd57a696..a34377e8 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/GroupBySchemaTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/GroupBySchemaTests.cs @@ -15,7 +15,7 @@ using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer { - class GroupBySchemaTests + internal sealed class GroupBySchemaTests { Mock factory; Mock node; diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Common.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Common.cs index d7eff4a2..ec6a2480 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Common.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Common.cs @@ -183,7 +183,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution { await service.HandleExecuteRequest(qeParams, requestContext); await service.WorkTask; - if (service.ActiveQueries.ContainsKey(qeParams.OwnerUri) && service.ActiveQueries[qeParams.OwnerUri].ExecutionTask != null) + if (service.ActiveQueries.TryGetValue(qeParams.OwnerUri, out Query? query) && query.ExecutionTask != null) { await service.ActiveQueries[qeParams.OwnerUri].ExecutionTask; } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsCsvFileStreamWriterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsCsvFileStreamWriterTests.cs index a14cbc5a..38a3b490 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsCsvFileStreamWriterTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsCsvFileStreamWriterTests.cs @@ -17,7 +17,7 @@ using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage { - public class SaveAsCsvFileStreamWriterTests + public partial class SaveAsCsvFileStreamWriterTests { [Test] public void Constructor_NullStream() @@ -148,7 +148,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage string output = writer.EncodeCsvField(field); // Then: It should wrap it in quotes - Assert.True(Regex.IsMatch(output, "^\".*\"$", RegexOptions.Singleline)); + Assert.True(GetCsvRegexSingleLine().IsMatch(output)); } [TestCase("Something\rElse")] // Contains carriage return [TODO: Don't support this] @@ -165,7 +165,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage string output = writer.EncodeCsvField(field); // Then: It should wrap it in quotes - Assert.True(Regex.IsMatch(output, @"^\[.*\[$", RegexOptions.Singleline)); + Assert.True(GetCsvBracketRegex().IsMatch(output)); } [TestCase("\tSomething")] // Starts with tab @@ -186,7 +186,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage string output = writer.EncodeCsvField(field); // Then: It should wrap it in quotes - Assert.True(Regex.IsMatch(output, "^\".*\"$", RegexOptions.Singleline)); + Assert.True(GetCsvRegexSingleLine().IsMatch(output)); } [TestCase("Something")] @@ -201,7 +201,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage string output = writer.EncodeCsvField(field); // Then: It should not wrap it in quotes - Assert.False(Regex.IsMatch(output, "^\".*\"$")); + Assert.False(GetCsvRegex().IsMatch(output)); } [TestCase(null, "Some\"thing", "\"Some\"\"thing\"")] // Default identifier @@ -277,7 +277,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage byte[] output = new byte[8192]; // If: I write a row - SaveAsCsvFileStreamWriter writer = new SaveAsCsvFileStreamWriter(new MemoryStream(output), requestParams, columns); + var writer = new SaveAsCsvFileStreamWriter(new MemoryStream(output), requestParams, columns); using (writer) { writer.WriteRow(data, columns); @@ -425,5 +425,14 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage Assert.IsEmpty(lines[lines.Length - 1]); return lines.Take(lines.Length - 1).ToArray(); } + + [GeneratedRegex("^\\[.*\\[$", RegexOptions.Singleline)] + private static partial Regex GetCsvBracketRegex(); + + [GeneratedRegex("^\".*\"$")] + private static partial Regex GetCsvRegex(); + + [GeneratedRegex("^\".*\"$", RegexOptions.Singleline)] + private static partial Regex GetCsvRegexSingleLine(); } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsExcelFileStreamWriterHelperTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsExcelFileStreamWriterHelperTests.cs index aca4487a..9a5d4eec 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsExcelFileStreamWriterHelperTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsExcelFileStreamWriterHelperTests.cs @@ -16,7 +16,7 @@ using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage { - public class SaveAsExcelFileStreamWriterHelperTests : IDisposable + public partial class SaveAsExcelFileStreamWriterHelperTests : IDisposable { private Stream _stream; public SaveAsExcelFileStreamWriterHelperTests() @@ -25,7 +25,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage using (var helper = new SaveAsExcelFileStreamWriterHelper(_stream, true)) using (var sheet = helper.AddSheet()) { - DbCellValue value = new DbCellValue(); + var value = new DbCellValue(); sheet.AddRow(); value.IsNull = true; @@ -71,7 +71,10 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage sheet.AddCell(value); } } - Regex contentRemoveLinebreakLeadingSpace = new Regex(@"\r?\n\s*"); + + [GeneratedRegex("\\r?\\n\\s*")] + private static partial Regex GetContentRemoveLinebreakLeadingSpaceRegex(); + private void ContentMatch(string fileName) { string referencePath = Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), @@ -79,11 +82,11 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage "SaveAsExcelFileStreamWriterHelperTests", fileName); string referenceContent = File.ReadAllText(referencePath); - referenceContent = contentRemoveLinebreakLeadingSpace.Replace(referenceContent, ""); + referenceContent = GetContentRemoveLinebreakLeadingSpaceRegex().Replace(referenceContent, ""); - using (ZipArchive zip = new ZipArchive(_stream, ZipArchiveMode.Read, true)) + using (var zip = new ZipArchive(_stream, ZipArchiveMode.Read, true)) { - using (var reader = new StreamReader(zip.GetEntry(fileName).Open())) + using (var reader = new StreamReader(zip?.GetEntry(fileName)?.Open()!)) { string realContent = reader.ReadToEnd(); Assert.AreEqual(referenceContent, realContent); @@ -130,7 +133,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage public class SaveAsExcelFileStreamWriterHelperReferenceManagerTests { private Mock _xmlWriterMock; - private string LastWrittenReference { get; set; } + private string? LastWrittenReference { get; set; } private int LastWrittenRow { get; set; } public SaveAsExcelFileStreamWriterHelperReferenceManagerTests() @@ -145,7 +148,6 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage _xmlWriterMock.Setup(a => a.WriteEndAttribute()); _xmlWriterMock.Setup(a => a.WriteValue(It.IsAny())) .Callback(row => LastWrittenRow = row); - } [Test] @@ -203,8 +205,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage manager.AssureColumnReference(); manager.WriteAndIncreaseColumnReference(); Assert.AreEqual("XFD1", LastWrittenReference); - var ex = Assert.Throws( - () => manager.AssureColumnReference()); + var ex = Assert.Throws(manager.AssureColumnReference); Assert.That(ex.Message, Does.Contain("max column number is 16384")); } [Test] @@ -232,8 +233,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage var xmlWriter = _xmlWriterMock.Object; var manager = new SaveAsExcelFileStreamWriterHelper.ReferenceManager(xmlWriter); - var ex = Assert.Throws( - () => manager.AssureColumnReference()); + var ex = Assert.Throws(manager.AssureColumnReference); Assert.That(ex.Message, Does.Contain("AddRow must be called before AddCell")); } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsMarkdownFileStreamWriterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsMarkdownFileStreamWriterTests.cs index 4c6963f5..36ee6f24 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsMarkdownFileStreamWriterTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/SaveAsMarkdownFileStreamWriterTests.cs @@ -18,10 +18,11 @@ using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage { - public class SaveAsMarkdownFileStreamWriterTests + public partial class SaveAsMarkdownFileStreamWriterTests { // Regex: Matches '|' not preceded by a '\' - private static readonly Regex UnescapedPipe = new Regex(@"(? expectedCells) { - string[] cells = UnescapedPipe.Split(line); + string[] cells = GetUnescapedPipeRegex().Split(line); string[] expectedCellsArray = expectedCells as string[] ?? expectedCells.ToArray(); Assert.That(cells.Length - 2, Is.EqualTo(expectedCellsArray.Length), "Wrong number of cells in output"); diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs index 153959d5..a36220dd 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs @@ -21,7 +21,7 @@ using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage { - public class ServiceBufferReaderWriterTests + public partial class ServiceBufferReaderWriterTests { [Test] public void ReaderStreamNull() @@ -49,7 +49,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage invalidStream.SetupGet(s => s.CanSeek).Returns(true); Assert.Throws(() => { - ServiceBufferFileStreamReader obj = new ServiceBufferFileStreamReader(invalidStream.Object, new QueryExecutionSettings()); + var obj = new ServiceBufferFileStreamReader(invalidStream.Object, new QueryExecutionSettings()); obj.Dispose(); }); } @@ -64,7 +64,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage invalidStream.SetupGet(s => s.CanSeek).Returns(false); Assert.Throws(() => { - ServiceBufferFileStreamReader obj = new ServiceBufferFileStreamReader(invalidStream.Object, new QueryExecutionSettings()); + var obj = new ServiceBufferFileStreamReader(invalidStream.Object, new QueryExecutionSettings()); obj.Dispose(); }); } @@ -95,7 +95,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage invalidStream.SetupGet(s => s.CanSeek).Returns(true); Assert.Throws(() => { - ServiceBufferFileStreamWriter obj = new ServiceBufferFileStreamWriter(invalidStream.Object, new QueryExecutionSettings()); + var obj = new ServiceBufferFileStreamWriter(invalidStream.Object, new QueryExecutionSettings()); obj.Dispose(); }); } @@ -110,7 +110,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage invalidStream.SetupGet(s => s.CanSeek).Returns(false); Assert.Throws(() => { - ServiceBufferFileStreamWriter obj = new ServiceBufferFileStreamWriter(invalidStream.Object, new QueryExecutionSettings()); + var obj = new ServiceBufferFileStreamWriter(invalidStream.Object, new QueryExecutionSettings()); obj.Dispose(); }); } @@ -128,7 +128,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage // If: // ... I write a type T to the writer - using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(new MemoryStream(storage), overrideSettings)) + using (var writer = new ServiceBufferFileStreamWriter(new MemoryStream(storage), overrideSettings)) { int writtenBytes = writeFunc(writer, value); Assert.AreEqual(valueLength, writtenBytes); @@ -136,7 +136,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage // ... And read the type T back FileStreamReadResult outValue; - using (ServiceBufferFileStreamReader reader = new ServiceBufferFileStreamReader(new MemoryStream(storage), overrideSettings)) + using (var reader = new ServiceBufferFileStreamReader(new MemoryStream(storage), overrideSettings)) { outValue = readFunc(reader, rowId); } @@ -312,7 +312,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; // Setup: Create a DATE column - DbColumnWrapper col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTe"}); + var col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTe"}); foreach (DateTime value in testValues) { @@ -320,7 +320,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage (reader, rowId) => reader.ReadDateTime(0, rowId, col)); // Make sure the display value does not have a time string - Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2}$")); + Assert.True(GetDateRegex().IsMatch(displayValue)); } } @@ -335,7 +335,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; // Setup: Create a DATETIME column - DbColumnWrapper col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTeTiMe"}); + var col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTeTiMe"}); foreach (DateTime value in testValues) { @@ -343,7 +343,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage (reader, rowId) => reader.ReadDateTime(0, rowId, col)); // Make sure the display value has a time string with 3 milliseconds - Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}\.[\d]{3}$")); + Assert.True(GetDateTimeRegex().IsMatch(displayValue)); } } @@ -358,7 +358,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; // Setup: Create a DATETIME column - DbColumnWrapper col = new DbColumnWrapper(new TestDbColumn + var col = new DbColumnWrapper(new TestDbColumn { DataTypeName = "DaTeTiMe2", NumericScale = precision @@ -370,7 +370,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage (reader, rowId) => reader.ReadDateTime(0, rowId, col)); // Make sure the display value has a time string with variable number of milliseconds - Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}")); + Assert.True(GetTimeRegex().IsMatch(displayValue)); if (precision > 0) { Assert.True(Regex.IsMatch(displayValue, $@"\.[\d]{{{precision}}}$")); @@ -389,7 +389,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; // Setup: Create a DATETIME2 column - DbColumnWrapper col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTeTiMe2", NumericScale = 0}); + var col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTeTiMe2", NumericScale = 0}); foreach (DateTime value in testValues) { @@ -397,7 +397,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage (reader, rowId) => reader.ReadDateTime(0, rowId, col)); // Make sure the display value has a time string with 0 milliseconds - Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}$")); + Assert.True(GetTimeRegex().IsMatch(displayValue)); } } @@ -412,7 +412,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; // Setup: Create a DATETIME2 column - DbColumnWrapper col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTeTiMe2", NumericScale = 255}); + var col = new DbColumnWrapper(new TestDbColumn {DataTypeName = "DaTeTiMe2", NumericScale = 255}); foreach (DateTime value in testValues) { @@ -420,7 +420,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage (reader, rowId) => reader.ReadDateTime(0, rowId, col)); // Make sure the display value has a time string with 7 milliseconds - Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}\.[\d]{7}$")); + Assert.True(GetDateTime2Regex().IsMatch(displayValue)); } } @@ -436,7 +436,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; // Setup: Create a DATETIMEOFFSET column - DbColumnWrapper col = new DbColumnWrapper(new TestDbColumn { DataTypeName = "datetimeoffset", NumericScale = 6 }); + var col = new DbColumnWrapper(new TestDbColumn { DataTypeName = "datetimeoffset", NumericScale = 6 }); foreach (DateTimeOffset value in testValues) { @@ -444,7 +444,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage (reader, rowId) => reader.ReadDateTimeOffset(0, rowId, col)); // Make sure the display value has a time string with 6 milliseconds and a time zone - Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}\.[\d]{6} [+-][01][\d]:[\d]{2}$")); + Assert.True(GetDateTimeOffset6Regex().IsMatch(displayValue)); } } @@ -458,7 +458,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; // Setup: Create a DATETIMEOFFSET column - DbColumnWrapper col = new DbColumnWrapper(new TestDbColumn { DataTypeName = "datetimeoffset", NumericScale = 0 }); + var col = new DbColumnWrapper(new TestDbColumn { DataTypeName = "datetimeoffset", NumericScale = 0 }); foreach (DateTimeOffset value in testValues) { @@ -466,7 +466,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage (reader, rowId) => reader.ReadDateTimeOffset(0, rowId, col)); // Make sure the display value has a time string with no millisecond and a time zone - Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2} [+-][01][\d]:[\d]{2}$")); + Assert.True(GetDateTimeOffset0Regex().IsMatch(displayValue)); } } @@ -490,11 +490,11 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage public void StringNullTest() { // Setup: Create a mock file stream - using (MemoryStream stream = new MemoryStream(new byte[8192])) + using (var stream = new MemoryStream(new byte[8192])) { // If: // ... I write null as a string to the writer - using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(stream, new QueryExecutionSettings())) + using (var writer = new ServiceBufferFileStreamWriter(stream, new QueryExecutionSettings())) { // Then: // ... I should get an argument null exception @@ -514,7 +514,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage { // Setup: // ... Generate the test value - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); for (int i = 0; i < length; i++) { sb.Append(values[i%values.Length]); @@ -529,11 +529,11 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage public void BytesNullTest() { // Setup: Create a mock file stream wrapper - using (MemoryStream stream = new MemoryStream(new byte[8192])) + using (var stream = new MemoryStream(new byte[8192])) { // If: // ... I write null as a string to the writer - using (ServiceBufferFileStreamWriter writer = new ServiceBufferFileStreamWriter(stream, new QueryExecutionSettings())) + using (var writer = new ServiceBufferFileStreamWriter(stream, new QueryExecutionSettings())) { // Then: // ... I should get an argument null exception @@ -554,7 +554,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage { // Setup: // ... Generate the test value - List sb = new List(); + var sb = new List(); for (int i = 0; i < length; i++) { sb.Add(values[i % values.Length]); @@ -602,5 +602,22 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage (reader, rowId) => reader.ReadMoney(0, rowId)); } } + + [GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2}$")] + private static partial Regex GetDateRegex(); + + [GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:[\\d]{2}:[\\d]{2}")] + private static partial Regex GetTimeRegex(); + + [GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:[\\d]{2}:[\\d]{2}\\.[\\d]{3}$")] + private static partial Regex GetDateTimeRegex(); + + [GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:[\\d]{2}:[\\d]{2}\\.[\\d]{7}$")] + private static partial Regex GetDateTime2Regex(); + + [GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:[\\d]{2}:[\\d]{2}\\.[\\d]{6} [+-][01][\\d]:[\\d]{2}$")] + private static partial Regex GetDateTimeOffset6Regex(); + [GeneratedRegex("^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:[\\d]{2}:[\\d]{2} [+-][01][\\d]:[\\d]{2}$")] + private static partial Regex GetDateTimeOffset0Regex(); } } \ No newline at end of file diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/BatchTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/BatchTests.cs index 4b8908e3..0455cee3 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/BatchTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/BatchTests.cs @@ -72,7 +72,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution BatchCallbackHelper(batch, b => batchStartCalls++, b => batchEndCalls++, - m => messages.Add(m), + messages.Add, r => resultSetCalls++); await batch.Execute(GetConnection(Common.CreateTestConnectionInfo(null, false, false)), CancellationToken.None); @@ -108,7 +108,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution BatchCallbackHelper(batch, b => batchStartCalls++, b => batchEndCalls++, - m => messages.Add(m), + messages.Add, r => resultSetCalls++); await batch.Execute(GetConnection(ci), CancellationToken.None); @@ -144,7 +144,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution BatchCallbackHelper(batch, b => batchStartCalls++, b => batchEndCalls++, - m => messages.Add(m), + messages.Add, r => resultSetCalls++); await batch.Execute(GetConnection(ci), CancellationToken.None); @@ -180,7 +180,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution BatchCallbackHelper(batch, b => batchStartCalls++, b => batchEndCalls++, - m => messages.Add(m), + messages.Add, r => resultSetCalls++); await batch.Execute(GetConnection(ci), CancellationToken.None); @@ -213,7 +213,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution BatchCallbackHelper(batch, b => batchStartCalls++, b => batchEndCalls++, - m => messages.Add(m), + messages.Add, r => { throw new Exception("ResultSet callback was called when it should not have been."); }); await batch.Execute(GetConnection(ci), CancellationToken.None); @@ -245,7 +245,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution BatchCallbackHelper(batch, b => batchStartCalls++, b => batchEndCalls++, - m => messages.Add(m), + messages.Add, r => { throw new Exception("ResultSet callback was called when it should not have been."); }); await batch.Execute(GetConnection(ci), CancellationToken.None); diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/DbColumnWrapperTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/DbColumnWrapperTests.cs index 00fb192d..28694719 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/DbColumnWrapperTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/DbColumnWrapperTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution /// /// Test DbColumn derived class /// - private class TestColumn : DbColumn + private sealed class TestColumn : DbColumn { public TestColumn( string dataTypeName = null, diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/QueryTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/QueryTests.cs index 58a2e28f..abdd631d 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/QueryTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/QueryTests.cs @@ -122,7 +122,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution BatchCallbackHelper(query, b => { throw new Exception("Batch startup callback should not have been called."); }, b => { throw new Exception("Batch completion callback was called"); }, - m => messages.Add(m)); + messages.Add); // If: // ... I Then execute the query @@ -235,7 +235,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution BatchCallbackHelper(query, b => { throw new Exception("Batch start handler was called"); }, b => { throw new Exception("Batch completed handler was called"); }, - m => messages.Add(m)); + messages.Add); // .. I then execute the query query.Execute(); @@ -271,7 +271,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution BatchCallbackHelper(query, b => batchStartCallbacksReceived++, b => batchCompletionCallbacksReceived++, - m => messages.Add(m)); + messages.Add); // ... I then execute the query query.Execute(); diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/ExecutionPlanTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/ExecutionPlanTests.cs index 249dd25f..8abbfc75 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/ExecutionPlanTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/ExecutionPlanTests.cs @@ -50,7 +50,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution // Then: // ... It should throw an exception - Assert.ThrowsAsync(() => planResultSet.GetExecutionPlan()); + Assert.ThrowsAsync(planResultSet.GetExecutionPlan); } #endregion diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/SaveResults/SerializationServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/SaveResults/SerializationServiceTests.cs index bf650f4f..de82b533 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/SaveResults/SerializationServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/SaveResults/SerializationServiceTests.cs @@ -375,11 +375,11 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.SaveResults } else if (column.DataTypeName == "Int") { - return Int64.Parse(value.DisplayValue.ToLower()); + return Int64.Parse(value.DisplayValue.ToLower(System.Globalization.CultureInfo.InvariantCulture)); } else if (column.DataTypeName == "Bit") { - return Boolean.Parse(value.DisplayValue.ToLower()); + return Boolean.Parse(value.DisplayValue.ToLower(System.Globalization.CultureInfo.InvariantCulture)); } return value.DisplayValue; } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/Azure/AzureAuthenticationManagerTest.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/Azure/AzureAuthenticationManagerTest.cs index 0f7e6aca..511fb1e1 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/Azure/AzureAuthenticationManagerTest.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/Azure/AzureAuthenticationManagerTest.cs @@ -53,7 +53,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ResourceProvider.Azure var currentUserAccount = CreateAccount(); currentUserAccount.Account.IsStale = true; IAzureAuthenticationManager accountManager = await CreateAccountManager(currentUserAccount, null); - Assert.ThrowsAsync(() => accountManager.GetSelectedSubscriptionsAsync()); + Assert.ThrowsAsync(accountManager.GetSelectedSubscriptionsAsync); } [Test] @@ -61,7 +61,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ResourceProvider.Azure { var currentUserAccount = CreateAccount(); IAzureAuthenticationManager accountManager = await CreateAccountManager(currentUserAccount, null, true); - Assert.ThrowsAsync(() => accountManager.GetSelectedSubscriptionsAsync()); + Assert.ThrowsAsync(accountManager.GetSelectedSubscriptionsAsync); } [Test] diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/Azure/AzureTestContext.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/Azure/AzureTestContext.cs index 61c29577..d47af55b 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/Azure/AzureTestContext.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/Azure/AzureTestContext.cs @@ -21,7 +21,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ResourceProvider.Azure /// /// A container to create test data and mock classes to test azure services and providers /// - internal class AzureTestContext + internal sealed class AzureTestContext { public AzureTestContext(Dictionary> subscriptionToDatabaseMap) { diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/FirewallRuleServiceTest.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/FirewallRuleServiceTest.cs index f737b365..4d24d010 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/FirewallRuleServiceTest.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ResourceProvider/FirewallRuleServiceTest.cs @@ -406,7 +406,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ResourceProvider } } - internal class ServiceTestContext + internal sealed class ServiceTestContext { private string _validServerName = "validServerName.database.windows.net"; private string _startIpAddressValue = "1.2.3.6"; diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/SqlProjects/SqlProjectTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/SqlProjects/SqlProjectTests.cs index 6bd26308..6018c522 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/SqlProjects/SqlProjectTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/SqlProjects/SqlProjectTests.cs @@ -21,7 +21,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.SqlProjects DatabaseVariable = "$(DatabaseVariable)" }; - Assert.Throws(() => reference.Validate(), $"Validate() for a reference with both {nameof(reference.DatabaseLiteral)} and {nameof(reference.DatabaseVariable)} should have failed"); + Assert.Throws(reference.Validate, $"Validate() for a reference with both {nameof(reference.DatabaseLiteral)} and {nameof(reference.DatabaseVariable)} should have failed"); // Verify that Validate() passes any other time reference = new AddDacpacReferenceParams() { DatabaseLiteral = "DatabaseName" }; diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/UtilityTests/ToSqlScriptTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/UtilityTests/ToSqlScriptTests.cs index b4a6fd90..da918f59 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/UtilityTests/ToSqlScriptTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/UtilityTests/ToSqlScriptTests.cs @@ -15,7 +15,7 @@ using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { - public class ToSqlScriptTests + public partial class ToSqlScriptTests { #region FormatValue Tests @@ -60,7 +60,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { // Setup: Build a column and cell for the integer type column DbColumn column = new FormatterTestDbColumn(dataType); - DbCellValue cell = new DbCellValue { RawObject = (long)123 }; + var cell = new DbCellValue { RawObject = (long)123 }; // If: I attempt to format an integer type column string output = ToSqlScript.FormatValue(cell, column); @@ -82,13 +82,13 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { // Setup: Build a column and cell for the decimal type column DbColumn column = new FormatterTestDbColumn(dataType, precision, scale); - DbCellValue cell = new DbCellValue { RawObject = 123.45m }; + var cell = new DbCellValue { RawObject = 123.45m }; // If: I attempt to format a decimal type column string output = ToSqlScript.FormatValue(cell, column); // Then: It should match a something like CAST(123.45 AS MONEY) - Regex castRegex = new Regex($@"CAST\([\d\.]+ AS {regex}", RegexOptions.IgnoreCase); + var castRegex = new Regex($@"CAST\([\d\.]+ AS {regex}", RegexOptions.IgnoreCase); Assert.True(castRegex.IsMatch(output)); } @@ -97,7 +97,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { // Setup: Build a column and cell for the approx numeric type column DbColumn column = new FormatterTestDbColumn("FLOAT"); - DbCellValue cell = new DbCellValue { RawObject = 3.14159d }; + var cell = new DbCellValue { RawObject = 3.14159d }; // If: I attempt to format a approx numeric type column string output = ToSqlScript.FormatValue(cell, column); @@ -111,7 +111,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { // Setup: Build a column and cell for the approx numeric type column DbColumn column = new FormatterTestDbColumn("REAL"); - DbCellValue cell = new DbCellValue { RawObject = (float)3.14159 }; + var cell = new DbCellValue { RawObject = (float)3.14159 }; // If: I attempt to format a approx numeric type column string output = ToSqlScript.FormatValue(cell, column); @@ -129,15 +129,14 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { // Setup: Build a column and cell for the datetime type column DbColumn column = new FormatterTestDbColumn(dataType); - DbCellValue cell = new DbCellValue { RawObject = DateTime.Now }; + var cell = new DbCellValue { RawObject = DateTime.Now }; // If: I attempt to format a datetime type column string output = ToSqlScript.FormatValue(cell, column); // Then: The output string should be able to be converted back into a datetime - Regex dateTimeRegex = new Regex("N'(.*)'"); DateTime outputDateTime; - Assert.True(DateTime.TryParse(dateTimeRegex.Match(output).Groups[1].Value, out outputDateTime)); + Assert.True(DateTime.TryParse(GetDateTimeRegex().Match(output).Groups[1].Value, out outputDateTime)); } [Test] @@ -145,15 +144,14 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { // Setup: Build a column and cell for the datetime offset type column DbColumn column = new FormatterTestDbColumn("DATETIMEOFFSET"); - DbCellValue cell = new DbCellValue { RawObject = DateTimeOffset.Now }; + var cell = new DbCellValue { RawObject = DateTimeOffset.Now }; // If: I attempt to format a datetime offset type column string output = ToSqlScript.FormatValue(cell, column); // Then: The output string should be able to be converted back into a datetime offset - Regex dateTimeRegex = new Regex("N'(.*)'"); DateTimeOffset outputDateTime; - Assert.True(DateTimeOffset.TryParse(dateTimeRegex.Match(output).Groups[1].Value, out outputDateTime)); + Assert.True(DateTimeOffset.TryParse(GetDateTimeRegex().Match(output).Groups[1].Value, out outputDateTime)); } [Test] @@ -161,15 +159,14 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { // Setup: Build a column and cell for the time type column DbColumn column = new FormatterTestDbColumn("TIME"); - DbCellValue cell = new DbCellValue { RawObject = TimeSpan.FromHours(12) }; + var cell = new DbCellValue { RawObject = TimeSpan.FromHours(12) }; // If: I attempt to format a time type column string output = ToSqlScript.FormatValue(cell, column); // Then: The output string should be able to be converted back into a timespan - Regex dateTimeRegex = new Regex("N'(.*)'"); TimeSpan outputDateTime; - Assert.True(TimeSpan.TryParse(dateTimeRegex.Match(output).Groups[1].Value, out outputDateTime)); + Assert.True(TimeSpan.TryParse(GetDateTimeRegex().Match(output).Groups[1].Value, out outputDateTime)); } private static readonly object[] stringFormats = @@ -186,7 +183,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests // Setup: Build a column and cell for the string type column // NOTE: We're using VARCHAR because it's very general purpose. DbColumn column = new FormatterTestDbColumn("VARCHAR"); - DbCellValue cell = new DbCellValue { RawObject = input }; + var cell = new DbCellValue { RawObject = input }; // If: I attempt to format a string type column string output = ToSqlScript.FormatValue(cell, column); @@ -208,7 +205,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { // Setup: Build a column and cell for the string type column DbColumn column = new FormatterTestDbColumn(datatype); - DbCellValue cell = new DbCellValue { RawObject = "test string" }; + var cell = new DbCellValue { RawObject = "test string" }; // If: I attempt to format a string type column string output = ToSqlScript.FormatValue(cell, column); @@ -222,17 +219,16 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { // Setup: Build a column and cell for the string type column DbColumn column = new FormatterTestDbColumn(datatype); - DbCellValue cell = new DbCellValue + var cell = new DbCellValue { - RawObject = new byte[] { 0x42, 0x45, 0x4e, 0x49, 0x53, 0x43, 0x4f, 0x4f, 0x4c } + RawObject = "BENISCOOL"u8.ToArray() }; // If: I attempt to format a string type column string output = ToSqlScript.FormatValue(cell, column); // Then: The output string should match the output string - Regex regex = new Regex("0x[0-9A-F]+", RegexOptions.IgnoreCase); - Assert.True(regex.IsMatch(output)); + Assert.True(GetOuputRegex().IsMatch(output)); } [Test] @@ -240,13 +236,13 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests { // Setup: Build a column and cell for the string type column DbColumn column = new FormatterTestDbColumn("UNIQUEIDENTIFIER"); - DbCellValue cell = new DbCellValue { RawObject = Guid.NewGuid() }; + var cell = new DbCellValue { RawObject = Guid.NewGuid() }; // If: I attempt to format a string type column string output = ToSqlScript.FormatValue(cell, column); // Then: The output string should match the output string - Regex regex = new Regex(@"N'[0-9A-F]{8}(-[0-9A-F]{4}){3}-[0-9A-F]{12}'", RegexOptions.IgnoreCase); + var regex = GetGuidRegex(); Assert.True(regex.IsMatch(output)); } @@ -391,7 +387,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests #endregion - private class FormatterTestDbColumn : DbColumn + private sealed class FormatterTestDbColumn : DbColumn { public FormatterTestDbColumn(string dataType, int? precision = null, int? scale = null, int? size = null) { @@ -401,5 +397,14 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests ColumnSize = size; } } + + [GeneratedRegex("0x[0-9A-F]+", RegexOptions.IgnoreCase, "en-CA")] + private static partial Regex GetOuputRegex(); + + [GeneratedRegex("N'[0-9A-F]{8}(-[0-9A-F]{4}){3}-[0-9A-F]{12}'", RegexOptions.IgnoreCase, "en-CA")] + private static partial Regex GetGuidRegex(); + + [GeneratedRegex("N'(.*)'")] + private static partial Regex GetDateTimeRegex(); } } \ No newline at end of file