public async Task TryLoadSqlProjectPropertiesAsync_IssueWarningIfNameNodeIsDifferentFromProjectName_Async()
        {
            // Arrange
            const string xml =
                @"<?xml version=""1.0"" encoding=""utf-8""?>
<Project>
  <PropertyGroup>
    <Name>TestProject</Name>
    <OutputPath>bin\Output</OutputPath>
    <DacVersion>2.2.3</DacVersion>
  </PropertyGroup>
</Project>";
            var project = new SqlProject("awesomeproject", @"C:\TestProject\TestProject.sqlproj", "c");
            var vsMock  = Mock.Of <IVersionService>();
            var fsaMock = new Mock <IFileSystemAccess>();

            fsaMock.Setup(m => m.ReadFileAsync(project.FullName))
            .ReturnsAsync(xml);
            var loggerMock             = new Mock <ILogger>();
            ISqlProjectService service = new SqlProjectService(vsMock, fsaMock.Object, loggerMock.Object);

            // Act
            var loadedSuccessfully = await service.TryLoadSqlProjectPropertiesAsync(project);

            // Assert
            Assert.IsTrue(loadedSuccessfully);
            loggerMock.Verify(m => m.LogErrorAsync(It.IsAny <string>()), Times.Never);
            loggerMock.Verify(m => m.LogErrorAsync(It.IsAny <Exception>(), It.IsAny <string>()), Times.Never);
            Assert.AreEqual("TestProject", project.ProjectProperties.SqlTargetName);
            Assert.AreEqual(@"C:\TestProject\bin\Output", project.ProjectProperties.BinaryDirectory);
            Assert.AreEqual(new Version(2, 2, 3), project.ProjectProperties.DacVersion);
            loggerMock.Verify(m => m.LogWarningAsync("XML node 'Name' doesn't match the actual project name. This could cause an unexpected behavior."), Times.Once);
            loggerMock.Verify(m => m.LogDebugAsync("Value of 'Name' node: TestProject"), Times.Once);
            loggerMock.Verify(m => m.LogDebugAsync("Actual project name: awesomeproject"), Times.Once);
        }
        public async Task TryLoadSqlProjectPropertiesAsync_Error_NoXmlRoot_Async()
        {
            // Arrange
            const string xml     = @"<?xml version=""1.0"" encoding=""utf-8""?>";
            var          project = new SqlProject("a", @"C:\TestProject.sqlproj", "c");
            var          vsMock  = Mock.Of <IVersionService>();
            var          fsaMock = new Mock <IFileSystemAccess>();

            fsaMock.Setup(m => m.ReadFileAsync(project.FullName))
            .ReturnsAsync(xml);
            var loggedErrorMessages = new List <(Exception Exception, string Message)>();
            var loggerMock          = new Mock <ILogger>();

            loggerMock.Setup(m => m.LogErrorAsync(It.IsAny <Exception>(), It.IsAny <string>()))
            .Callback((Exception e, string message) => loggedErrorMessages.Add((e, message)))
            .Returns(Task.CompletedTask);
            ISqlProjectService service = new SqlProjectService(vsMock, fsaMock.Object, loggerMock.Object);

            // Act
            var loadedSuccessfully = await service.TryLoadSqlProjectPropertiesAsync(project);

            // Assert
            Assert.IsFalse(loadedSuccessfully);
            Assert.AreEqual(1, loggedErrorMessages.Count);
            Assert.IsNotNull(loggedErrorMessages[0]);
            Assert.IsNotNull(loggedErrorMessages[0].Exception);
            Assert.IsTrue(loggedErrorMessages[0].Message.StartsWith(@"Cannot read contents of ""C:\TestProject.sqlproj"""));
        }
        public async Task TryLoadSqlProjectPropertiesAsync_UseNameIfSqlTargetNameIsEmpty_Async()
        {
            // Arrange
            const string xml =
                @"<?xml version=""1.0"" encoding=""utf-8""?>
<Project>
  <PropertyGroup>
    <Name>TestProject</Name>
    <OutputPath>bin\Output</OutputPath>
    <DacVersion>2.2.3</DacVersion>
    <SqlTargetName></SqlTargetName>
  </PropertyGroup>
</Project>";
            var project = new SqlProject("a", @"C:\TestProject\TestProject.sqlproj", "c");
            var vsMock  = Mock.Of <IVersionService>();
            var fsaMock = new Mock <IFileSystemAccess>();

            fsaMock.Setup(m => m.ReadFileAsync(project.FullName))
            .ReturnsAsync(xml);
            var loggerMock             = new Mock <ILogger>();
            ISqlProjectService service = new SqlProjectService(vsMock, fsaMock.Object, loggerMock.Object);

            // Act
            var loadedSuccessfully = await service.TryLoadSqlProjectPropertiesAsync(project);

            // Assert
            Assert.IsTrue(loadedSuccessfully);
            loggerMock.Verify(m => m.LogErrorAsync(It.IsAny <string>()), Times.Never);
            loggerMock.Verify(m => m.LogErrorAsync(It.IsAny <Exception>(), It.IsAny <string>()), Times.Never);
            Assert.AreEqual("TestProject", project.ProjectProperties.SqlTargetName);
            Assert.AreEqual(@"C:\TestProject\bin\Output", project.ProjectProperties.BinaryDirectory);
            Assert.AreEqual(new Version(2, 2, 3), project.ProjectProperties.DacVersion);
        }
        public async Task TryLoadSqlProjectPropertiesAsync_Error_NoOutputPath_Async()
        {
            // Arrange
            const string xml =
                @"<?xml version=""1.0"" encoding=""utf-8""?>
<Project>
  <PropertyGroup>
    <Name>TestProject</Name>
  </PropertyGroup>
</Project>";
            var project = new SqlProject("a", @"C:\TestProject.sqlproj", "c");
            var vsMock  = Mock.Of <IVersionService>();
            var fsaMock = new Mock <IFileSystemAccess>();

            fsaMock.Setup(m => m.ReadFileAsync(project.FullName))
            .ReturnsAsync(xml);
            var loggedErrorMessages = new List <string>();
            var loggerMock          = new Mock <ILogger>();

            loggerMock.Setup(m => m.LogErrorAsync(It.IsAny <string>()))
            .Callback((string message) => loggedErrorMessages.Add(message))
            .Returns(Task.CompletedTask);
            ISqlProjectService service = new SqlProjectService(vsMock, fsaMock.Object, loggerMock.Object);

            // Act
            var loadedSuccessfully = await service.TryLoadSqlProjectPropertiesAsync(project);

            // Assert
            Assert.IsFalse(loadedSuccessfully);
            Assert.AreEqual(1, loggedErrorMessages.Count);
            Assert.AreEqual(@"Cannot read output path of ""C:\TestProject.sqlproj"". " +
                            "Please make sure that the \"OutputPath\" for the current configuration is set correctly, e.g. \"bin\\Output\\\". " +
                            "This value can be set from your database project => \"Properties\" => \"Build\" => \"Output path\".",
                            loggedErrorMessages[0]);
        }
        public async Task TryLoadSqlProjectPropertiesAsync_Error_NoName_Async()
        {
            // Arrange
            const string xml =
                @"<?xml version=""1.0"" encoding=""utf-8""?>
<Project>
  <PropertyGroup>
  </PropertyGroup>
</Project>";
            var project = new SqlProject("a", @"C:\TestProject.sqlproj", "c");
            var vsMock  = Mock.Of <IVersionService>();
            var fsaMock = new Mock <IFileSystemAccess>();

            fsaMock.Setup(m => m.ReadFileAsync(project.FullName))
            .ReturnsAsync(xml);
            var loggedErrorMessages = new List <string>();
            var loggerMock          = new Mock <ILogger>();

            loggerMock.Setup(m => m.LogErrorAsync(It.IsAny <string>()))
            .Callback((string message) => loggedErrorMessages.Add(message))
            .Returns(Task.CompletedTask);
            ISqlProjectService service = new SqlProjectService(vsMock, fsaMock.Object, loggerMock.Object);

            // Act
            var loadedSuccessfully = await service.TryLoadSqlProjectPropertiesAsync(project);

            // Assert
            Assert.IsFalse(loadedSuccessfully);
            Assert.AreEqual(1, loggedErrorMessages.Count);
            Assert.AreEqual(@"Cannot read name of ""C:\TestProject.sqlproj"". " +
                            "Please make sure that the \"Name\" is set correctly, e.g. \"MyDatabaseProject\". " +
                            "This value has to be set manually in XML.",
                            loggedErrorMessages[0]);
        }
        public void TryLoadSqlProjectPropertiesAsync_ArgumentNullException_Project()
        {
            // Arrange
            var vsMock                 = Mock.Of <IVersionService>();
            var fsaMock                = Mock.Of <IFileSystemAccess>();
            var loggerMock             = Mock.Of <ILogger>();
            ISqlProjectService service = new SqlProjectService(vsMock, fsaMock, loggerMock);

            // Act & Assert
            // ReSharper disable once AssignNullToNotNullAttribute
            Assert.Throws <ArgumentNullException>(() => service.TryLoadSqlProjectPropertiesAsync(null));
        }
        public async Task TryLoadSqlProjectPropertiesAsync_Error_NoProjectDirectory_Async()
        {
            // Arrange
            var project        = new SqlProject("a", @"C:\", "c");
            var vsMock         = Mock.Of <IVersionService>();
            var fsaMock        = Mock.Of <IFileSystemAccess>();
            var loggedMessages = new List <string>();
            var loggerMock     = new Mock <ILogger>();

            loggerMock.Setup(m => m.LogErrorAsync(It.IsAny <string>()))
            .Callback((string message) => loggedMessages.Add(message))
            .Returns(Task.CompletedTask);
            ISqlProjectService service = new SqlProjectService(vsMock, fsaMock, loggerMock.Object);

            // Act
            var loadedSuccessfully = await service.TryLoadSqlProjectPropertiesAsync(project);

            // Assert
            Assert.IsFalse(loadedSuccessfully);
            Assert.AreEqual(1, loggedMessages.Count);
            Assert.AreEqual(@"Cannot get project directory for C:\", loggedMessages[0]);
        }