diff --git a/Packages.props b/Packages.props index 9d18e879..9b8c20d4 100644 --- a/Packages.props +++ b/Packages.props @@ -13,6 +13,7 @@ + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj b/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj index e9eca682..a5114f2c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj +++ b/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj @@ -51,6 +51,7 @@ + diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs index 00cad9a2..53274822 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs @@ -32,8 +32,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects }, requestMock.Object); - Assert.IsFalse(requestMock.Result.Success); - Assert.IsTrue(requestMock.Result.ErrorMessage!.Contains("Cannot create a new SQL project")); + Assert.IsFalse(requestMock.Result.Success, $"{nameof(service.HandleNewSqlProjectRequest)} when file already exists expected to fail"); + Assert.IsTrue(requestMock.Result.ErrorMessage!.Contains("Cannot create a new SQL project") + && requestMock.Result.ErrorMessage!.Contains("a file already exists at that location"), + $"Error message expected to mention that a file already exists, but instead was: '{requestMock.Result.ErrorMessage}'"); } [Test] @@ -48,7 +50,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects SqlProjectsService service = new(); - Assert.AreEqual(0, service.Projects.Count); + Assert.AreEqual(0, service.Projects.Count, "Baseline number of loaded projects"); // Validate creating SDK-style project MockRequest requestMock = new(); @@ -56,13 +58,12 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects { ProjectUri = sdkProjectUri, SqlProjectType = ProjectType.SdkStyle - }, requestMock.Object); - Assert.IsTrue(requestMock.Result.Success); - Assert.AreEqual(1, service.Projects.Count); - Assert.IsTrue(service.Projects.ContainsKey(sdkProjectUri)); - Assert.AreEqual(service.Projects[sdkProjectUri].SqlProjStyle, ProjectType.SdkStyle); + requestMock.AssertSuccess(nameof(service.HandleNewSqlProjectRequest), "SDK"); + Assert.AreEqual(1, service.Projects.Count, "Number of loaded projects after creating SDK not as expected"); + Assert.IsTrue(service.Projects.ContainsKey(sdkProjectUri), "Loaded project list expected to contain SDK project URI"); + Assert.AreEqual(ProjectType.SdkStyle, service.Projects[sdkProjectUri].SqlProjStyle, "SqlProj style expected to be SDK"); // Validate creating Legacy-style project requestMock = new(); @@ -72,26 +73,26 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects SqlProjectType = ProjectType.LegacyStyle }, requestMock.Object); - Assert.IsTrue(requestMock.Result.Success); - Assert.AreEqual(2, service.Projects.Count); - Assert.IsTrue(service.Projects.ContainsKey(legacyProjectUri)); - Assert.AreEqual(service.Projects[legacyProjectUri].SqlProjStyle, ProjectType.LegacyStyle); + requestMock.AssertSuccess(nameof(service.HandleNewSqlProjectRequest), "Legacy"); + Assert.AreEqual(2, service.Projects.Count, "Number of loaded projects after creating Legacy"); + Assert.IsTrue(service.Projects.ContainsKey(legacyProjectUri), "Loaded project list expected to contain Legacy project URI"); + Assert.AreEqual(service.Projects[legacyProjectUri].SqlProjStyle, ProjectType.LegacyStyle, "SqlProj style"); // Validate closing a project requestMock = new(); await service.HandleCloseSqlProjectRequest(new SqlProjectParams() { ProjectUri = sdkProjectUri }, requestMock.Object); - Assert.IsTrue(requestMock.Result.Success); - Assert.AreEqual(1, service.Projects.Count); - Assert.IsTrue(!service.Projects.ContainsKey(sdkProjectUri)); + requestMock.AssertSuccess(nameof(service.HandleCloseSqlProjectRequest)); + Assert.AreEqual(1, service.Projects.Count, "Number of loaded projects after closing SDK project"); + Assert.IsTrue(!service.Projects.ContainsKey(sdkProjectUri), "Loaded project list should not contain SDK after closing"); // Validate opening a project requestMock = new(); await service.HandleOpenSqlProjectRequest(new SqlProjectParams() { ProjectUri = sdkProjectUri }, requestMock.Object); - Assert.IsTrue(requestMock.Result.Success); - Assert.AreEqual(2, service.Projects.Count); - Assert.IsTrue(service.Projects.ContainsKey(sdkProjectUri)); + requestMock.AssertSuccess(nameof(service.HandleOpenSqlProjectRequest)); + Assert.AreEqual(2, service.Projects.Count, "Number of loaded projects after re-opening"); + Assert.IsTrue(service.Projects.ContainsKey(sdkProjectUri), "Loaded project list expected to contain SDK project URI after re-opening"); } [Test] @@ -100,13 +101,14 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects // Setup SqlProjectsService service = new(); string projectUri = await service.CreateSqlProject(); - Assert.AreEqual(0, service.Projects[projectUri].SqlObjectScripts.Count); + Assert.AreEqual(0, service.Projects[projectUri].SqlObjectScripts.Count, "Baseline number of SqlObjectScripts"); // Validate adding a SQL object script MockRequest requestMock = new(); string scriptRelativePath = "MyTable.sql"; string scriptFullPath = Path.Join(Path.GetDirectoryName(projectUri), scriptRelativePath); await File.WriteAllTextAsync(scriptFullPath, "CREATE TABLE [MyTable] ([Id] INT)"); + Assert.IsTrue(File.Exists(scriptFullPath), $"{scriptFullPath} expected to be on disk"); await service.HandleAddSqlObjectScriptRequest(new SqlProjectScriptParams() { @@ -114,9 +116,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects Path = scriptRelativePath }, requestMock.Object); - Assert.IsTrue(requestMock.Result.Success); - Assert.AreEqual(1, service.Projects[projectUri].SqlObjectScripts.Count); - Assert.IsTrue(service.Projects[projectUri].SqlObjectScripts.Contains(scriptRelativePath)); + requestMock.AssertSuccess(nameof(service.HandleAddSqlObjectScriptRequest)); + Assert.AreEqual(1, service.Projects[projectUri].SqlObjectScripts.Count, "SqlObjectScripts count after add"); + Assert.IsTrue(service.Projects[projectUri].SqlObjectScripts.Contains(scriptRelativePath), $"SqlObjectScripts expected to contain {scriptRelativePath}"); // Validate excluding a SQL object script requestMock = new(); @@ -126,9 +128,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects Path = scriptRelativePath }, requestMock.Object); - Assert.IsTrue(requestMock.Result.Success); - Assert.AreEqual(0, service.Projects[projectUri].SqlObjectScripts.Count); - Assert.IsTrue(File.Exists(scriptFullPath)); + requestMock.AssertSuccess(nameof(service.HandleExcludeSqlObjectScriptRequest)); + Assert.AreEqual(0, service.Projects[projectUri].SqlObjectScripts.Count, "SqlObjectScripts count after exclude"); + Assert.IsTrue(File.Exists(scriptFullPath), $"{scriptFullPath} expected to still exist on disk"); // Re-add to set up for Delete requestMock = new(); @@ -138,8 +140,8 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects Path = scriptRelativePath }, requestMock.Object); - Assert.IsTrue(requestMock.Result.Success); - Assert.AreEqual(1, service.Projects[projectUri].SqlObjectScripts.Count); + requestMock.AssertSuccess(nameof(service.HandleAddSqlObjectScriptRequest)); + Assert.AreEqual(1, service.Projects[projectUri].SqlObjectScripts.Count, "SqlObjectScripts count after re-add"); // Validate deleting a SQL object script requestMock = new(); @@ -149,9 +151,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects Path = scriptRelativePath }, requestMock.Object); - Assert.IsTrue(requestMock.Result.Success); - Assert.AreEqual(0, service.Projects[projectUri].SqlObjectScripts.Count); - Assert.IsFalse(File.Exists(scriptFullPath)); + requestMock.AssertSuccess(nameof(service.HandleDeleteSqlObjectScriptRequest)); + Assert.AreEqual(0, service.Projects[projectUri].SqlObjectScripts.Count, "SqlObjectScripts count after delete"); + Assert.IsFalse(File.Exists(scriptFullPath), $"{scriptFullPath} expected to have been deleted from disk"); } } @@ -174,7 +176,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects }, requestMock.Object); - Assert.IsTrue(requestMock.Result.Success); + Assert.IsTrue(requestMock.Result.Success, $"Failed to create project: {requestMock.Result.ErrorMessage}"); return projectUri; } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/RequestContextMocking/RequestContextMocks.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/RequestContextMocking/RequestContextMocks.cs index ea102224..bdcaa9f3 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/RequestContextMocking/RequestContextMocks.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/RequestContextMocking/RequestContextMocks.cs @@ -7,7 +7,9 @@ using System; using System.Threading.Tasks; using Microsoft.SqlTools.Hosting.Protocol; using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.SqlTools.ServiceLayer.Utility; using Moq; +using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.Test.Common.RequestContextMocking { @@ -61,7 +63,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common.RequestContextMocking } } - public class MockRequest + public class MockRequest where T : ResultStatus { private T? result; public T Result => result ?? throw new InvalidOperationException("No result has been sent for the request"); @@ -73,5 +75,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common.RequestContextMocking { Mock = RequestContextMocks.Create(actual => result = actual); } + + /// + /// Asserts that this request was successful + /// + /// Name of the handler, recommended to use nameof(service.MyHandler), used in the failure message + /// Optional extra descriptor, parenthesized in the failure message + public void AssertSuccess(string handlerName, string? descriptor = null) + { + Assert.IsTrue(this.Result.Success, $"{handlerName}{(descriptor != null ? $" ({descriptor})" : String.Empty)} expected to succeed, but failed with error: '{this.Result.ErrorMessage}'"); + } } }