Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SLVS-1678 Use unique generated compilation database names #5875

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ public void GetOrNull_CmakeAvailable_ReturnsCmakeLocation()

var result = testSubject.GetOrNull("some path");

result.Should().Be(location);
result.Should().BeOfType<ExternalCompilationDatabaseHandle>().And.BeEquivalentTo(new ExternalCompilationDatabaseHandle(location));
vcx.DidNotReceiveWithAnyArgs().CreateOrNull(default);
}

[TestMethod]
public void GetOrNull_CmakeUnavailable_VcxAvailable_ReturnsVcxLocation()
{
var sourcePath = "some path";
var location = "some location";
var location = Substitute.For<ICompilationDatabaseHandle>();
cmake.Locate().ReturnsNull();
vcx.CreateOrNull(sourcePath).Returns(location);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using SonarLint.VisualStudio.CFamily.CompilationDatabase;

namespace SonarLint.VisualStudio.CFamily.UnitTests.CompilationDatabase;

[TestClass]
public class ExternalCompilationDatabaseHandleTests
{
[TestMethod]
public void Ctor_AssignsExpectedValues()
{
const string filePath = "some path";
var testSubject = new ExternalCompilationDatabaseHandle(filePath);

testSubject.FilePath.Should().BeSameAs(filePath);
}

[TestMethod]
public void Ctor_NullPath_Throws()
{
var act = () => new ExternalCompilationDatabaseHandle(null);

act.Should().Throw<ArgumentNullException>().Which.ParamName.Should().Be("filePath");
}

[TestMethod]
public void Dispose_NoOp_DoesNotThrow()
{
var act = () => new ExternalCompilationDatabaseHandle("some path").Dispose();

act.Should().NotThrow();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ internal class AggregatingCompilationDatabaseProvider(
IVCXCompilationDatabaseProvider vcxCompilationDatabaseProvider)
: IAggregatingCompilationDatabaseProvider
{
public string GetOrNull(string sourceFilePath)
public ICompilationDatabaseHandle GetOrNull(string sourceFilePath)
{
if (cMakeCompilationDatabaseLocator.Locate() is {} cmakeCompilationDatabasePath)
{
return cmakeCompilationDatabasePath;
return new ExternalCompilationDatabaseHandle(cmakeCompilationDatabasePath);
}

return vcxCompilationDatabaseProvider.CreateOrNull(sourceFilePath);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using SonarLint.VisualStudio.Core.CFamily;

namespace SonarLint.VisualStudio.CFamily.CompilationDatabase;

internal sealed class ExternalCompilationDatabaseHandle(string filePath) : ICompilationDatabaseHandle
{
public string FilePath { get; } = filePath ?? throw new ArgumentNullException(nameof(filePath));

public void Dispose()
{
// do nothing
}
}
4 changes: 3 additions & 1 deletion src/CFamily/IVCXCompilationDatabaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using SonarLint.VisualStudio.Core.CFamily;

namespace SonarLint.VisualStudio.CFamily;

public interface IVCXCompilationDatabaseProvider
{
string CreateOrNull(string filePath);
ICompilationDatabaseHandle CreateOrNull(string filePath);
}
8 changes: 7 additions & 1 deletion src/Core/CFamily/IAggregatingCompilationDatabaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,11 @@ namespace SonarLint.VisualStudio.Core.CFamily;

public interface IAggregatingCompilationDatabaseProvider
{
string GetOrNull(string sourceFilePath);
ICompilationDatabaseHandle GetOrNull(string sourceFilePath);
}

public interface ICompilationDatabaseHandle : IDisposable
{
string FilePath { get; }
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System.IO.Abstractions;
using NSubstitute.ReceivedExtensions;
using SonarLint.VisualStudio.Integration.Vsix.CFamily.VcxProject;

namespace SonarLint.VisualStudio.Integration.UnitTests.CFamily.VcxProject;

[TestClass]
public class TemporaryCompilationDatabaseHandleTests
{
private const string FilePath = "some path";
private IFile file;
private TestLogger logger;
private TemporaryCompilationDatabaseHandle testSubject;

[TestInitialize]
public void TestInitialize()
{
file = Substitute.For<IFile>();
logger = new TestLogger();
testSubject = new TemporaryCompilationDatabaseHandle(FilePath, file, logger);
}

[DataRow("path1")]
[DataRow(@"path1\path2")]
[DataTestMethod]
public void Ctor_AssignsExpectedValues(string path) =>
new TemporaryCompilationDatabaseHandle(path, default, default).FilePath.Should().BeSameAs(path);

[TestMethod]
public void Ctor_NullPath_Throws()
{
var act = () => new TemporaryCompilationDatabaseHandle(null, default, default);

act.Should().Throw<ArgumentNullException>().Which.ParamName.Should().Be("filePath");
}

[TestMethod]
public void Dispose_DeletesFile()
{
testSubject.Dispose();

file.Received().Delete(FilePath);
logger.AssertNoOutputMessages();
}

[TestMethod]
public void Dispose_MultipleTimes_ActsOnlyOnce()
{
testSubject.Dispose();
testSubject.Dispose();
testSubject.Dispose();

file.ReceivedWithAnyArgs(1).Delete(default);
}

[TestMethod]
public void Dispose_CatchesAndLogsExceptions()
{
var exception = new Exception("testexc");
file.When(x => x.Delete(Arg.Any<string>())).Throw(exception);

var act = () => testSubject.Dispose();

act.Should().NotThrow();
logger.AssertPartialOutputStringExists(exception.ToString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

using NSubstitute.ReturnsExtensions;
using SonarLint.VisualStudio.CFamily;
using SonarLint.VisualStudio.Core.CFamily;
using SonarLint.VisualStudio.Integration.Vsix.CFamily.VcxProject;

namespace SonarLint.VisualStudio.Integration.UnitTests.CFamily.VcxProject;
Expand Down Expand Up @@ -74,13 +75,13 @@ public void CreateOrNull_FileConfig_CantStore_ReturnsNull()
}

[TestMethod]
public void CreateOrNull_FileConfig_StoresAndReturnsPath()
public void CreateOrNull_FileConfig_StoresAndReturnsHandle()
{
const string databasePath = "database path";
var fileConfig = Substitute.For<IFileConfig>();
fileConfigProvider.Get(SourceFilePath, default).Returns(fileConfig);
storage.CreateDatabase(fileConfig).Returns(databasePath);
var compilationDatabaseHandle = Substitute.For<ICompilationDatabaseHandle>();
storage.CreateDatabase(fileConfig).Returns(compilationDatabaseHandle);

testSubject.CreateOrNull(SourceFilePath).Should().Be(databasePath);
testSubject.CreateOrNull(SourceFilePath).Should().Be(compilationDatabaseHandle);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,32 @@ public void CreateDatabase_CriticalException_Throws()
public void CreateDatabase_FileWritten_ReturnsPathToDatabaseWithCorrectContent()
{
var expectedDirectory = Path.Combine(Path.GetTempPath(), "SLVS", "VCXCD", PathHelper.PerVsInstanceFolderName.ToString());
var expectedPath = Path.Combine(expectedDirectory, $"{SourceFileName}.{SourceFilePath.GetHashCode()}.json");
var fileConfig = SetUpFileConfig();

var databasePath = testSubject.CreateDatabase(fileConfig);
var databaseHandle = testSubject.CreateDatabase(fileConfig);

databasePath.Should().Be(expectedPath);
var temporaryCompilationDatabaseHandle = databaseHandle.Should().BeOfType<TemporaryCompilationDatabaseHandle>().Subject;
Directory.GetParent(temporaryCompilationDatabaseHandle.FilePath).FullName.Should().BeEquivalentTo(expectedDirectory);
Path.GetExtension(temporaryCompilationDatabaseHandle.FilePath).Should().Be(".json");
threadHandling.Received().ThrowIfOnUIThread();
fileSystemService.Directory.Received().CreateDirectory(expectedDirectory);
fileSystemService.File.Received().WriteAllText(expectedPath, Arg.Any<string>());
fileSystemService.File.Received().WriteAllText(temporaryCompilationDatabaseHandle.FilePath, Arg.Any<string>());
VerifyDatabaseContents();
}

[TestMethod]
public void CreateDatabase_CreatesDifferentHandlesForSameFile()
{
var expectedDirectory = Path.Combine(Path.GetTempPath(), "SLVS", "VCXCD", PathHelper.PerVsInstanceFolderName.ToString());
var fileConfig = SetUpFileConfig();

var databaseHandle1 = testSubject.CreateDatabase(fileConfig);
var databaseHandle2 = testSubject.CreateDatabase(fileConfig);

Directory.GetParent(databaseHandle1.FilePath).FullName.Should().BeEquivalentTo(expectedDirectory);
Directory.GetParent(databaseHandle2.FilePath).FullName.Should().BeEquivalentTo(expectedDirectory);
Path.GetFileNameWithoutExtension(databaseHandle1.FilePath).Should().NotBe(Path.GetFileNameWithoutExtension(databaseHandle2.FilePath));
}

[TestMethod]
public void CreateDatabase_Disposed_Throws()
Expand All @@ -114,11 +128,33 @@ public void Dispose_RemovesDirectory()
{
var expectedDirectory = Path.Combine(Path.GetTempPath(), "SLVS", "VCXCD", PathHelper.PerVsInstanceFolderName.ToString());

testSubject.Dispose();

fileSystemService.Directory.Received().Delete(expectedDirectory, true);
testLogger.AssertNoOutputMessages();
}

[TestMethod]
public void Dispose_MultipleTimes_ActsOnlyOnce()
{
testSubject.Dispose();
testSubject.Dispose();
testSubject.Dispose();

fileSystemService.Directory.Received(1).Delete(expectedDirectory, true);
fileSystemService.Directory.ReceivedWithAnyArgs(1).Delete(default, default);
}


[TestMethod]
public void Dispose_CatchesAndLogsException()
{
var exception = new Exception("testexc");
fileSystemService.Directory.When(x => x.Delete(Arg.Any<string>(), Arg.Any<bool>())).Throw(exception);

var act = () => testSubject.Dispose();

act.Should().NotThrow();
testLogger.AssertPartialOutputStringExists(exception.ToString());
}

private static IFileConfig SetUpFileConfig()
Expand Down
Loading
Loading