Skip to content

Commit

Permalink
SLVS-1678 Use unique generated compilation database names (#5875)
Browse files Browse the repository at this point in the history
  • Loading branch information
georgii-borovinskikh-sonarsource committed Dec 9, 2024
1 parent 1f0fe81 commit 4b7a22b
Show file tree
Hide file tree
Showing 14 changed files with 422 additions and 159 deletions.
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

0 comments on commit 4b7a22b

Please sign in to comment.