Skip to content
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
52 changes: 52 additions & 0 deletions PowerKit.Tests/LockFileTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.IO;
using FluentAssertions;
using PowerKit;
using Xunit;

namespace PowerKit.Tests;

public class LockFileTests
{
[Fact]
public void TryAcquire_Test()
{
// Arrange
using var tempFile = TempFile.Create();

// Act
using var lockFile = LockFile.TryAcquire(tempFile.Path);

// Assert
lockFile.Should().NotBeNull();
File.Exists(tempFile.Path).Should().BeTrue();
}

[Fact]
public void TryAcquire_AlreadyLocked_Test()
{
// Arrange
using var tempFile = TempFile.Create();
using var lockFile = LockFile.TryAcquire(tempFile.Path);

// Act
using var lockFile2 = LockFile.TryAcquire(tempFile.Path);

// Assert
lockFile2.Should().BeNull();
}

[Fact]
public void Dispose_Test()
{
// Arrange
using var tempFile = TempFile.Create();
var lockFile = LockFile.TryAcquire(tempFile.Path);

// Act
lockFile!.Dispose();

// Assert: lock can be reacquired after disposal
using var lockFile2 = LockFile.TryAcquire(tempFile.Path);
lockFile2.Should().NotBeNull();
}
}
40 changes: 40 additions & 0 deletions PowerKit/LockFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.IO;

namespace PowerKit;

/// <summary>
/// Represents a file-based lock that prevents concurrent access to a shared resource.
/// </summary>
internal partial class LockFile(FileStream fileStream) : IDisposable
{
/// <inheritdoc />
public void Dispose() => fileStream.Dispose();
}

internal partial class LockFile
{
/// <summary>
/// Tries to acquire a lock on the specified file path.
/// Returns <see langword="null" /> if the lock could not be acquired.
/// </summary>
public static LockFile? TryAcquire(string filePath)
{
try
{
var fileStream = File.Open(
filePath,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.None
);

return new LockFile(fileStream);
}
// This is the most specific exception for "access denied"
catch (IOException)
{
return null;
Comment thread
Tyrrrz marked this conversation as resolved.
}
}
}