fix: Reject non-name key inputs in simulate-keyboard#2013
Conversation
Enum.TryParse accepted far more than key names: ordinals ("3" resolved to
Key.Tab), signed ordinals ("+3"), whitespace-padded input, comma-separated
names OR-ed into one value ("Space,Enter"), and undefined ordinals ("300")
that passed the Key.None guard and then threw ArgumentOutOfRangeException
from the keyboard indexer. Runs that pressed an unrelated key still reported
Success: true, so verification results silently described the wrong input.
Resolve a key only when the normalized name matches a name defined on the
Key enum, and route everything else to the existing suggester error path.
KeyboardKeyNameSuggester is unchanged; its digit suggestions were already
implemented but unreachable because TryParse succeeded first.
- Add an immutable OrdinalIgnoreCase whitelist of Enum.GetNames(typeof(Key))
- Explain the ordinal history when rejecting numeric input, so earlier
results and scripts that passed digits get re-checked
- Add "Digit3" to the example key names in both validation messages
📝 WalkthroughWalkthroughThe ChangesKeyboard validation
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
Assets/Tests/PlayMode/SimulateKeyboardTests.cs (1)
637-707: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAssert the new numeric guidance, not only rejection.
These tests prove
Success == false, but do not consistently verify the new"Digits are not key names"and prior-results warning text. Add those assertions so the remediation contract cannot regress while validation still fails.Suggested assertions
Assert.IsFalse(lastResponse.Success, "A bare digit must not be accepted as a Key enum ordinal"); + StringAssert.Contains("Digits are not key names", lastResponse.Message); + StringAssert.Contains("re-check any earlier results", lastResponse.Message); Assert.IsFalse(lastResponse.Success, "A signed numeric key must not be accepted as a Key enum ordinal"); + StringAssert.Contains("Digits are not key names", lastResponse.Message); + StringAssert.Contains("re-check any earlier results", lastResponse.Message);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Assets/Tests/PlayMode/SimulateKeyboardTests.cs` around lines 637 - 707, Extend the failure assertions in Press_WithBareDigitKey_Should_ReturnFailureSuggestingDigitAndNumpad, Press_WithSignedNumericKey_Should_ReturnFailure, Press_WithCommaSeparatedKeyNames_Should_ReturnFailure, and Press_WithUndefinedNumericKey_Should_ReturnFailure to verify the response message includes the new “Digits are not key names” guidance and the prior-results warning text. Preserve the existing Success, candidate-name, and validation assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@Assets/Tests/PlayMode/SimulateKeyboardTests.cs`:
- Around line 637-707: Extend the failure assertions in
Press_WithBareDigitKey_Should_ReturnFailureSuggestingDigitAndNumpad,
Press_WithSignedNumericKey_Should_ReturnFailure,
Press_WithCommaSeparatedKeyNames_Should_ReturnFailure, and
Press_WithUndefinedNumericKey_Should_ReturnFailure to verify the response
message includes the new “Digits are not key names” guidance and the
prior-results warning text. Preserve the existing Success, candidate-name, and
validation assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: d833752a-1c24-4b62-805c-54f7693d7a25
📒 Files selected for processing (2)
Assets/Tests/PlayMode/SimulateKeyboardTests.csPackages/src/Editor/FirstPartyTools/SimulateKeyboard/SimulateKeyboardUseCase.cs
Rejecting a digit is only half the contract: the message must also explain that bare digits used to resolve to unrelated keys, so earlier results get re-checked. Pin that text so it cannot regress while rejection still works. Applies to the numeric cases only. "Space,Enter" is not numeric input, so it is rejected without the digit guidance and its test must not assert it.
|
Addressed in cc6fa41 — thanks. Applied to the three numeric cases ( Not applied to Verified: PlayMode |
Self-review findings on the whitelist change.
- Match ASCII digits explicitly. char.IsDigit is also true for non-ASCII
digits, which Enum.TryParse never accepted as ordinals, so the message
would have claimed an earlier run pressed another key when it did not.
- Assert that a whitelisted name parses, stating the invariant the two-step
resolution relies on.
- Cover whitespace-padded digits (" 3 "), another input Enum.TryParse used
to read as an ordinal.
- Pin the comma-separated case: it must report an invalid key name and must
not carry the digit guidance, which is scoped to numeric input.
The whitelist made padded correct input fail. Enum.TryParse used to trim, so "--key ' Space '" already worked and rejecting it would break valid scripts. Blocking ambiguous input must not narrow correct input. Trim once at the input entry point so the Return-to-Enter alias also sees the padded form. " 3 " still fails: after trimming it is "3", which is not a name defined on the Key enum, so the numeric block is unaffected. - Suggest candidates from the normalized name, while the error message keeps reporting the raw input verbatim - Cover padded valid names and the padded alias
…only Review follow-up on the key name whitelist. - Replace the name set plus Enum.TryParse round-trip with a single immutable name-to-value map, which drops the second lookup, the invariant assert, and the provisional key value. The Key.None guard stays: "None" is a defined name and still must not resolve. - Cover case-insensitive resolution, which no test pinned before: swapping the comparer for Ordinal left every test green while breaking "--key space". - Cover Digit3 itself, the name the rejection message advertises. - Match ASCII digits in KeyboardKeyNameSuggester as well. char.IsDigit is true for non-ASCII digits such as "3", so it suggested a Digit3 name that no Key value has.
b68da26
into
feature/cli-discoverability-integration
Summary
simulate-keyboard --keynow fails loudly on inputs that are not Input SystemKeynames, instead of silently pressing an unrelated key.Digit3/Numpad3) and warns that earlier runs may have pressed something else.User Impact
Before,
--key 3returnedSuccess: trueand pressedTab.Enum.TryParseaccepted much more than key names:3Success: true, pressedTab(parsed as the enum ordinal)+3Success: true, same ordinal pathSpace,EnterSuccess: true, comma-separated names OR-ed into one value300Key.Noneguard, then threwArgumentOutOfRangeExceptionfrom the keyboard indexerA run that pressed the wrong key still reported success, so verification results silently described input that never happened — the worst case for anyone using these results as evidence.
After this change all four inputs return
Success: falsewith a candidate list. Rejecting a numeric key also states that bare digits used to be parsed as enum ordinals (e.g."3"pressedTab), so earlier results and scripts that passed digits can be re-checked rather than trusted.Correct input is not narrowed.
--key Returnkeeps working through the existingReturntoEnteralias, and whitespace-padded names such as--key " Space "keep resolving —Enum.TryParseused to trim, so padded correct input already worked and rejecting it would break valid scripts." 3 "still fails, because after trimming it is3, which is not a name defined on theKeyenum.Changes
Keyenum, using an immutable case-insensitive whitelist built fromEnum.GetNames(typeof(Key)).char.IsDigitis also true for non-ASCII digits, whichEnum.TryParsenever read as ordinals, so the message would otherwise claim an earlier run pressed another key when it did not.Key.Noneguard and route every rejection through the existing suggester error path, preserving theInvalid key namewording that tests pin.KeyboardKeyNameSuggesterkeeps its suggestion logic. Its digit suggestions were already implemented but unreachable for1-9, becauseEnum.TryParseresolved those to a key before the suggester could run.0was the exception: it parsed toKey.Noneand was caught by the guard, so that one digit did reach the suggester.char.IsDigitis true for non-ASCII digits such as3, which would have suggested aDigit3name that noKeyvalue has.Digit3to the example key names in both validation messages, so the error-prone form appears where the mistake is made.Verification
Tests were written first and confirmed failing before the fix (4 red, plus the
Returnalias case green), then re-run after it.uloop compile—ErrorCount: 0,WarningCount: 0uloop run-tests --test-mode PlayModefiltered toSimulateKeyboardTests— 47 tests, 47 passed, 0 faileduloop run-tests --test-mode EditModefiltered toKeyboardKeyNameSuggesterTests— 3 tests, 3 passed, 0 faileduloop run-tests --test-mode EditModefiltered toStaticFacadeStateGuardTests— 20 tests, 20 passed, 0 failed, confirming the newstatic readonlylookup does not trip the mutable-static guardRed-state evidence before the fix:
--key "3"/"+3"/"Space,Enter"each failed withExpected: False But was: True, and--key "300"failed with an unhandledArgumentOutOfRangeException, confirming both silent-success paths and the exception path.Note on CI: repository workflows are scoped to
pull_request.branches [main, v3-beta], so none of them run on a pull request targeting this integration branch. The results above are local runs; CI validation happens on the final integration pull request.