From a7acb2bb2134def2401c59f7708d7c3cbc523221 Mon Sep 17 00:00:00 2001 From: Matthew Edmondson Date: Sun, 27 Sep 2026 03:27:10 +0000 Subject: [PATCH] Guard blank command ids in the active-profile lookup overloads [patch] GetChord, UnbindChord and HasChordBinding(commandId) forwarded straight to the Profile methods, which throw on a blank id, so the result depended on whether a profile happened to be active. They now return null/false for a blank id, as the (profileId, commandId) overloads already do. Fixes #129 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G89GFC9HBcemu37GarNas1 --- Keybinding.Test/BlankCommandIdTests.cs | 41 ++++++++++++++++++++++++ Keybinding/Services/KeybindingService.cs | 15 +++++++++ 2 files changed, 56 insertions(+) create mode 100644 Keybinding.Test/BlankCommandIdTests.cs diff --git a/Keybinding.Test/BlankCommandIdTests.cs b/Keybinding.Test/BlankCommandIdTests.cs new file mode 100644 index 0000000..5e4021b --- /dev/null +++ b/Keybinding.Test/BlankCommandIdTests.cs @@ -0,0 +1,41 @@ +// Copyright (c) 2023-2026 ktsu-dev contributors + +namespace ktsu.Keybinding.Test; + +using ktsu.Keybinding.Core.Services; + +[TestClass] +public class BlankCommandIdTests +{ + private ProfileManager _profiles = null!; + private KeybindingService _service = null!; + + [TestInitialize] + public void Setup() + { + _profiles = new ProfileManager(); + _profiles.CreateProfile("p", "Profile"); + _service = new KeybindingService(new CommandRegistry(), _profiles); + } + + [TestMethod] + [DataRow("")] + [DataRow(" ")] + [DataRow(null)] + public void ActiveProfileOverloads_BlankCommandId_MatchTheProfileIdOverloads(string? commandId) + { + Assert.IsNull(_service.GetChord(commandId!)); + Assert.IsFalse(_service.UnbindChord(commandId!)); + Assert.IsFalse(_service.HasChordBinding(commandId!)); + + _profiles.SetActiveProfile("p"); + + Assert.IsNull(_service.GetChord(commandId!), "GetChord should not depend on whether a profile is active."); + Assert.IsFalse(_service.UnbindChord(commandId!), "UnbindChord should not depend on whether a profile is active."); + Assert.IsFalse(_service.HasChordBinding(commandId!), "HasChordBinding should not depend on whether a profile is active."); + + Assert.AreEqual(_service.GetChord("p", commandId!), _service.GetChord(commandId!)); + Assert.AreEqual(_service.UnbindChord("p", commandId!), _service.UnbindChord(commandId!)); + Assert.AreEqual(_service.HasChordBinding("p", commandId!), _service.HasChordBinding(commandId!)); + } +} diff --git a/Keybinding/Services/KeybindingService.cs b/Keybinding/Services/KeybindingService.cs index d73f78f..4647d48 100644 --- a/Keybinding/Services/KeybindingService.cs +++ b/Keybinding/Services/KeybindingService.cs @@ -89,6 +89,11 @@ public bool BindChord(string profileId, string commandId, Chord chord) /// public Chord? GetChord(string commandId) { + if (string.IsNullOrWhiteSpace(commandId)) + { + return null; + } + Profile? activeProfile = _profileManager.GetActiveProfile(); return activeProfile?.GetChord(commandId); } @@ -127,6 +132,11 @@ public IReadOnlyDictionary GetAllChords(string profileId) /// public bool UnbindChord(string commandId) { + if (string.IsNullOrWhiteSpace(commandId)) + { + return false; + } + Profile? activeProfile = _profileManager.GetActiveProfile(); return activeProfile?.RemoveChord(commandId) ?? false; } @@ -249,6 +259,11 @@ public Chord ParseChord(string chordString) /// public bool HasChordBinding(string commandId) { + if (string.IsNullOrWhiteSpace(commandId)) + { + return false; + } + Profile? activeProfile = _profileManager.GetActiveProfile(); return activeProfile?.HasChord(commandId) ?? false; }