Skip to content

Normalize the key in the Note(NoteName) constructor as the string one does - #126

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/note-name-ctor-normalize-121
Sep 27, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/note-name-ctor-normalize-121

Conversation

@matt-edmondson

@matt-edmondson matt-edmondson commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #121

What was wrong

The [JsonConstructor] Note(NoteName) overload passed key.ToString() straight to CanonicalizeKey, which only matches uppercase text. It did not trim or uppercase first, although the string overload does both. As a result, new Note(NoteName.Create("control")) stayed control rather than becoming CTRL, and "s" stayed lowercase. Chord.ToString() uppercases for display, so the broken chord still printed as Ctrl+S, yet it was not equal to Chord.Parse("Ctrl+S"). Bindings built this way never matched.

Change

Both constructors now call one private NormalizeKey(string) helper, which does CanonicalizeKey(key.Trim().ToUpperInvariant()). The NoteName overload still reuses the caller's NoteName instance when normalizing leaves it unchanged.

Tests

  • EveryConstructionPath_NormalizesModifierAliases now also builds chords from NoteName.Create(alias) and NoteName.Create(alias.ToLowerInvariant()) with a lowercase NoteName.Create("s"). Before, it only fed that constructor pre-uppercased input, which is why the bug got through.
  • New NoteNameConstructor_MatchesStringConstructor checks new Note(NoteName.Create(x)) == new Note(x), including the hash code and key text, for control, Control, ctrl, s, f5 and " cmd ".
  • With the fix reverted, 11 tests fail. With the fix, all 93 pass (Linux/net10.0).

🤖 Generated with Claude Code

https://claude.ai/code/session_013qSqApi9HSiBjyHaJQYPTP

… does

The [JsonConstructor] Note(NoteName) overload canonicalized the key without
trimming or uppercasing it first, so NoteName "control" stayed "control"
rather than becoming CTRL, and "s" stayed lowercase. Chord.ToString()
uppercases for display, so the resulting chord printed as "Ctrl+S" but was
not equal to Chord.Parse("Ctrl+S"). Both constructors now go through one
NormalizeKey helper.

Fixes #121

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013qSqApi9HSiBjyHaJQYPTP
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Note(NoteName) doesn't uppercase before canonicalizing, so a chord built from NoteName "control" shows "Ctrl+S" but isn't equal to Chord.Parse("Ctrl+S")

1 participant