Skip to content
Open
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
70 changes: 70 additions & 0 deletions Keybinding.Test/NullChordArgumentTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Keybinding.Test;

using ktsu.Keybinding.Core.Models;
using ktsu.Keybinding.Core.Services;

[TestClass]
public class NullChordArgumentTests
{
private ProfileManager _profiles = null!;
private CommandRegistry _commands = null!;
private KeybindingService _service = null!;

[TestInitialize]
public void Setup()
{
_profiles = new ProfileManager();
_commands = new CommandRegistry();
_commands.RegisterCommand(new Command("save", "Save"));
_service = new KeybindingService(_commands, _profiles);
}

[TestMethod]
public void ActiveProfileOverloads_NullChord_ThrowWithNoActiveProfile()
{
Assert.IsNull(_service.ActiveProfile);

Assert.ThrowsExactly<ArgumentNullException>(() => _service.BindChord("save", null!));
Assert.ThrowsExactly<ArgumentNullException>(() => _service.ExecuteChord(null!));
Assert.ThrowsExactly<ArgumentNullException>(() => _service.FindCommandByChord(null!));
}

[TestMethod]
public void ActiveProfileOverloads_NullChord_ThrowWithAnActiveProfile()
{
_profiles.CreateProfile("default", "Default");
_profiles.SetActiveProfile("default");
Assert.IsNotNull(_service.ActiveProfile);

Assert.ThrowsExactly<ArgumentNullException>(() => _service.BindChord("save", null!));
Assert.ThrowsExactly<ArgumentNullException>(() => _service.ExecuteChord(null!));
Assert.ThrowsExactly<ArgumentNullException>(() => _service.FindCommandByChord(null!));
}

[TestMethod]
[DataRow("")]
[DataRow(" ")]
[DataRow(null)]
[DataRow("missing")]
public void ProfileIdOverloads_NullChord_ThrowWhateverTheProfileId(string? profileId)
{
Assert.ThrowsExactly<ArgumentNullException>(() => _service.BindChord(profileId!, "save", null!));
Assert.ThrowsExactly<ArgumentNullException>(() => _service.ExecuteChord(profileId!, null!));
Assert.ThrowsExactly<ArgumentNullException>(() => _service.FindCommandByChord(profileId!, null!));
}

[TestMethod]
[DataRow("")]
[DataRow(" ")]
[DataRow(null)]
public void BindChord_NullChord_ThrowsWhateverTheCommandId(string? commandId)
{
_profiles.CreateProfile("default", "Default");
_profiles.SetActiveProfile("default");

Assert.ThrowsExactly<ArgumentNullException>(() => _service.BindChord(commandId!, null!));
Assert.ThrowsExactly<ArgumentNullException>(() => _service.BindChord(_service.ActiveProfile!.Id, commandId!, null!));
}
}
6 changes: 6 additions & 0 deletions Keybinding/Contracts/IKeybindingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public interface IKeybindingService
/// A chord runs one command per profile. Binding a chord that another command in the profile already uses
/// moves it: the other command loses that binding, as rebinding a shortcut does in most editors.
/// </remarks>
/// <exception cref="ArgumentNullException">Thrown when chord is null, whether or not a profile is active and whatever the profile ID</exception>
public bool BindChord(string commandId, Chord chord);

/// <summary>
Expand All @@ -73,6 +74,7 @@ public interface IKeybindingService
/// A chord runs one command per profile. Binding a chord that another command in the profile already uses
/// moves it: the other command loses that binding, as rebinding a shortcut does in most editors.
/// </remarks>
/// <exception cref="ArgumentNullException">Thrown when chord is null, whether or not a profile is active and whatever the profile ID</exception>
public bool BindChord(string profileId, string commandId, Chord chord);

/// <summary>
Expand Down Expand Up @@ -151,6 +153,7 @@ public interface IKeybindingService
/// </summary>
/// <param name="chord">The chord that was pressed</param>
/// <returns>The command ID that was executed, null if no binding found</returns>
/// <exception cref="ArgumentNullException">Thrown when chord is null, whether or not a profile is active and whatever the profile ID</exception>
public string? ExecuteChord(Chord chord);

/// <summary>
Expand All @@ -159,6 +162,7 @@ public interface IKeybindingService
/// <param name="profileId">The profile ID</param>
/// <param name="chord">The chord that was pressed</param>
/// <returns>The command ID that was executed, null if no binding found</returns>
/// <exception cref="ArgumentNullException">Thrown when chord is null, whether or not a profile is active and whatever the profile ID</exception>
public string? ExecuteChord(string profileId, Chord chord);

/// <summary>
Expand All @@ -182,6 +186,7 @@ public interface IKeybindingService
/// </summary>
/// <param name="chord">The chord to search for</param>
/// <returns>The command ID if found, null otherwise</returns>
/// <exception cref="ArgumentNullException">Thrown when chord is null, whether or not a profile is active and whatever the profile ID</exception>
public string? FindCommandByChord(Chord chord);

/// <summary>
Expand All @@ -191,5 +196,6 @@ public interface IKeybindingService
/// <param name="profileId">The profile ID</param>
/// <param name="chord">The chord to search for</param>
/// <returns>The command ID if found, null otherwise</returns>
/// <exception cref="ArgumentNullException">Thrown when chord is null, whether or not a profile is active and whatever the profile ID</exception>
public string? FindCommandByChord(string profileId, Chord chord);
}
10 changes: 8 additions & 2 deletions Keybinding/Services/KeybindingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
throw new ArgumentException("Profile ID cannot be null or whitespace", nameof(id));
}

ArgumentException.ThrowIfNullOrWhiteSpace(name, nameof(name));

Check warning on line 39 in Keybinding/Services/KeybindingService.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Remove this argument from the method call; it hides the caller information.

Check warning on line 39 in Keybinding/Services/KeybindingService.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Remove this argument from the method call; it hides the caller information.

Check warning on line 39 in Keybinding/Services/KeybindingService.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Remove this argument from the method call; it hides the caller information.

Check warning on line 39 in Keybinding/Services/KeybindingService.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Remove this argument from the method call; it hides the caller information.

Check warning on line 39 in Keybinding/Services/KeybindingService.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Remove this argument from the method call; it hides the caller information.

Check warning on line 39 in Keybinding/Services/KeybindingService.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Remove this argument from the method call; it hides the caller information.

return _profileManager.CreateProfile(id, name, description);
}
Expand All @@ -52,13 +52,17 @@
/// <inheritdoc/>
public bool BindChord(string commandId, Chord chord)
{
Ensure.NotNull(chord);

Profile? activeProfile = _profileManager.GetActiveProfile();
return activeProfile is not null && BindChord(activeProfile.Id, commandId, chord);
}

/// <inheritdoc/>
public bool BindChord(string profileId, string commandId, Chord chord)
{
Ensure.NotNull(chord);

if (string.IsNullOrWhiteSpace(profileId))
{
return false;
Expand All @@ -69,8 +73,6 @@
return false;
}

Ensure.NotNull(chord);

Profile? profile = _profileManager.GetProfile(profileId);
if (profile is null)
{
Expand Down Expand Up @@ -201,6 +203,8 @@
/// <inheritdoc/>
public string? ExecuteChord(Chord chord)
{
Ensure.NotNull(chord);

Profile? activeProfile = _profileManager.GetActiveProfile();
return activeProfile is not null ? ExecuteChord(activeProfile.Id, chord) : null;
}
Expand Down Expand Up @@ -249,6 +253,8 @@
/// <inheritdoc/>
public string? FindCommandByChord(Chord chord)
{
Ensure.NotNull(chord);

Profile? activeProfile = _profileManager.GetActiveProfile();
return activeProfile is not null ? FindCommandByChord(activeProfile.Id, chord) : null;
}
Expand Down
Loading