From 6d10be6655ffcdefc26edcf629a615e70cf4af70 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 22:28:13 +0000 Subject: [PATCH] Refuse a blank NoteName in the Note constructor [patch] Note(string) threw for a null or whitespace key, but Note(NoteName) trimmed it to "" and went on to build an empty note. A chord holding it displayed as "Ctrl+", bound and executed, and was then dropped on the next load because the stored key could not be read back. Both constructors now throw the same ArgumentException, as their docs already say. Fixes #212 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017vfJW547mxaz1R4r27gAVm --- Keybinding.Test/BlankNoteNameTests.cs | 34 +++++++++++++++++++++++++++ Keybinding/Models/MusicalTypes.cs | 5 ++++ 2 files changed, 39 insertions(+) create mode 100644 Keybinding.Test/BlankNoteNameTests.cs diff --git a/Keybinding.Test/BlankNoteNameTests.cs b/Keybinding.Test/BlankNoteNameTests.cs new file mode 100644 index 0000000..8ac1504 --- /dev/null +++ b/Keybinding.Test/BlankNoteNameTests.cs @@ -0,0 +1,34 @@ +// Copyright (c) 2023-2026 ktsu-dev contributors + +namespace ktsu.Keybinding.Test; + +using ktsu.Keybinding.Core.Models; + +[TestClass] +public class BlankNoteNameTests +{ + [TestMethod] + [DataRow("")] + [DataRow(" ")] + [DataRow("\t")] + public void NoteFromBlankNoteName_ThrowsArgumentException(string key) + { + // The string constructor already refused a blank key; the NoteName one built an empty note that + // displayed as "Ctrl+", executed, and was then dropped when the profile was loaded again (#212). + NoteName name = NoteName.Create(key); + ArgumentException exception = Assert.ThrowsExactly(() => new Note(name)); + Assert.AreEqual("key", exception.ParamName); + Assert.StartsWith("Key cannot be null or whitespace", exception.Message); + } + + [TestMethod] + [DataRow("")] + [DataRow(" ")] + [DataRow("\t")] + public void NoteFromBlankString_ThrowsTheSameArgumentException(string key) + { + ArgumentException exception = Assert.ThrowsExactly(() => new Note(key)); + Assert.AreEqual("key", exception.ParamName); + Assert.StartsWith("Key cannot be null or whitespace", exception.Message); + } +} diff --git a/Keybinding/Models/MusicalTypes.cs b/Keybinding/Models/MusicalTypes.cs index 7cfc33c..762a9ad 100644 --- a/Keybinding/Models/MusicalTypes.cs +++ b/Keybinding/Models/MusicalTypes.cs @@ -19,6 +19,11 @@ public sealed class Note : IEquatable public Note(NoteName key) { Ensure.NotNull(key); + if (string.IsNullOrWhiteSpace(key.ToString())) + { + throw new ArgumentException("Key cannot be null or whitespace", nameof(key)); + } + string canonical = NormalizeKey(key.ToString()); Key = canonical == key.ToString() ? key : NoteName.Create(canonical); }