Skip to content

fix: add expression eval to input macros, fuzz infrastructure, String() fixes#14

Merged
wizzomafizzo merged 4 commits into
mainfrom
fix/input-macro-expression-eval
Apr 14, 2026
Merged

fix: add expression eval to input macros, fuzz infrastructure, String() fixes#14
wizzomafizzo merged 4 commits into
mainfrom
fix/input-macro-expression-eval

Conversation

@wizzomafizzo
Copy link
Copy Markdown
Member

@wizzomafizzo wizzomafizzo commented Apr 14, 2026

Summary

  • Add [[expression]] evaluation support to input macro commands (input.keyboard, input.gamepad), fixing Input macro commands don't support expression evaluation #2
  • Add FuzzParseTagFilters and FuzzCommandString fuzz targets with round-trip property testing
  • Fix multiple Command.String() serialization bugs found by fuzzing:
    • Normalize command name before isInputMacroCmd check (mixed case used wrong parser)
    • Quote args containing *, [, #, {, ' characters
    • Escape [ inside quoted args to prevent expression parsing
    • Escape \, ?, [, {, | in input macro output
    • Quote explicit empty string args as "" to distinguish from no args
    • Skip empty arg when colon has no content (argWritten tracking)
  • Add fuzz task to Taskfile with configurable FUZZ_TIME
  • Add dedicated nightly fuzz.yml workflow with crash artifact upload and auto-issue creation
  • Remove inline fuzz from CI (corpus regressions still run via go test)

Closes #2

Summary by CodeRabbit

  • New Features

    • Input macros can include expression interpolation within arguments.
  • Tests

    • Added dedicated fuzz test targets and expanded fuzz corpus.
    • Extended parsing tests for more edge cases around macro arguments.
  • Chores

    • Moved fuzz testing to a separate scheduled/manual workflow and added a reusable fuzz task with crash reporting.

Input macro commands (input.keyboard, input.gamepad) processed characters
one at a time with no expression handling, causing [[expression]] syntax
to be split into individual characters instead of being evaluated.

Closes #2
…trip bugs

Add FuzzParseTagFilters and FuzzCommandString fuzz targets. The round-trip
fuzzer (parse → String() → reparse) found and fixed several serialization
bugs in Command.String():

- Normalize command name before isInputMacroCmd check (mixed case used wrong parser)
- Quote args containing *, [, #, {, ' in String() output
- Escape [ inside quoted args to prevent expression parsing
- Escape \, ?, [, {, | in input macro String() output
- Quote explicit empty string args as "" to distinguish from no args
- Skip empty arg when colon has no content (argWritten tracking)

Add fuzz task to Taskfile.yml matching zaparoo-core's pattern with
configurable FUZZ_TIME. Add dedicated nightly fuzz.yml workflow with crash
artifact upload and automatic issue creation. Remove inline fuzz from CI
(corpus regressions still run via go test).
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 76537b70-e784-4f93-9157-2a853cd29e0a

📥 Commits

Reviewing files that changed from the base of the PR and between 46beba7 and db20c1e.

📒 Files selected for processing (3)
  • parser.go
  • parser_mutation_test.go
  • reader.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • parser.go
  • reader.go

📝 Walkthrough

Walkthrough

Reorganizes fuzz testing into a dedicated scheduled workflow, adds a Taskfile fuzz task and multiple fuzz tests/corpus seeds, implements expression interpolation for input-macro args and refines arg-empty vs missing semantics, normalizes command names, and updates argument serialization/escaping logic.

Changes

Cohort / File(s) Summary
CI/Workflow Infrastructure
.github/workflows/ci.yml, .github/workflows/fuzz.yml
Removes the inline fuzz job from main CI and adds a new fuzz.yml workflow (cron @ 02:00 UTC + manual dispatch) that runs task fuzz, times out at 120m, caches Go, uploads crash corpus artifacts on failure, and auto-creates a GitHub issue with run link and repro instructions.
Build Task Configuration
Taskfile.yml
Adds a fuzz task with configurable FUZZ_TIME (default "30s"), executing five fuzz targets and aggregating per-target PASS/FAIL into a single exit status.
Parser/Argument Handling
arguments.go, parser.go, symbols.go
Adds SymExpressionStart handling inside parseInputMacroArg; introduces labeled loop control and argWritten tracking to distinguish explicit empty args from missing ones; applies normalizeCmdName() for command-name normalization during parsing.
Serialization & Reader Logic
reader.go
Expands argNeedsQuoting() to include additional marker runes, updates escapeArg() to escape expression-start tokens, and changes Command.String() to handle input-macro arg verbatim emission only when wrapped with input-macro ext markers and to force quoting for empty args.
Fuzz Tests & Corpus
parser_fuzz_test.go, testdata/fuzz/FuzzCommandString/*
Adds fuzzers FuzzParseTagFilters and FuzzCommandString (round-trip via cmd.String() + cmp.Diff) and seeds multiple new corpus entries exercising input-macro forms, escapes, expressions, and edge cases.
Parser Tests / Coverage
parser_coverage_test.go, parser_mutation_test.go
Adds coverage cases validating expression tokenization inside input macros and updates mutation tests to reflect the distinction between missing args and explicit empty quoted args.

Sequence Diagram(s)

mermaid
sequenceDiagram
rect rgba(95,159,159,0.5)
participant Trigger as Trigger (cron / workflow_dispatch)
participant GitHub as GitHub Actions
participant Runner as Runner (ubuntu-latest)
end
rect rgba(159,95,159,0.5)
participant Checkout as actions/checkout
participant SetupGo as actions/setup-go
participant Task as arduino/setup-task + task
participant Artifacts as Artifact Storage
participant GHCLI as gh (GitHub API)
end

Trigger->>GitHub: start fuzz.yml
GitHub->>Runner: schedule job (120m timeout)
Runner->>Checkout: checkout repo
Runner->>SetupGo: setup Go (from go.mod)
Runner->>Task: install Task, run `task fuzz` (FUZZ_TIME)
alt fuzz run succeeds
    Task-->>Runner: exit 0
else fuzz run fails / crashes found
    Task-->>Runner: non-zero, produce crash corpus under **/testdata/fuzz/**
    Runner->>Artifacts: upload `fuzz-crashes` artifact (ignore-missing=false)
    Runner->>GHCLI: create issue with run link and repro steps
end
Runner-->>GitHub: job complete

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped through tokens, nibbling gaps so slight,

Expressions stitched into input macros overnight,
Fuzz seeds scattered, round-trips guard the gate,
Empty args now whisper—present or absent, they state,
A tiny bug-hunt dance beneath the CI lights.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the PR's primary changes: adding expression evaluation to input macros, establishing fuzz infrastructure, and fixing String() serialization bugs.
Linked Issues check ✅ Passed The PR fully addresses issue #2 by adding SymExpressionStart handling to parseInputMacroArg in arguments.go, enabling expression evaluation in input.keyboard and input.gamepad macro arguments.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the stated objectives: expression support in input macros, fuzz infrastructure setup, and Command.String() bug fixes discovered through fuzzing.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/input-macro-expression-eval

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/fuzz.yml:
- Around line 1-75: The workflow pins an unverified commit for the
arduino/setup-task action (uses:
arduino/setup-task@b91d5d2c96a56797b48ac1e0e89220bf64044611) instead of the
official v2.0.0 release SHA; update the uses entry for the Task setup step to
reference the verified v2.0.0 commit (SHA
24c5e13bce349197642746563945fcdf9359e8f4) so the step that sets up Task
(Taskfile.yml) is pinned to the correct, audited release.

In `@parser_mutation_test.go`:
- Around line 811-819: Add a paired explicit-empty test row next to the "empty
arg from colon only" case in the parser_mutation_test.go table to ensure
`**cmd:""` and `**cmd:''` parse to an explicit empty arg (Args: []string{""})
rather than being treated as omitted; update the test table that constructs
zapscript.Script with Cmds containing zapscript.Command{Name: "cmd", Args:
[]string{""}} for those inputs so the parser's empty-vs-omitted behavior is
covered.

In `@parser.go`:
- Around line 206-209: The current usage of hasArgs(args) in the auto-launch
parsing path drops explicit empty arguments parsed by parseArgs (which sets
argWritten) and causes inputs like "" or ""?launcher=x to lose the
caller-intended empty target; remove the broad hasArgs(args) check in this
location and instead preserve args when parseArgs indicated an explicit write
(check argWritten or equivalent from parseArgs) so cmd.Args remains the explicit
empty string when provided, and move any hasArgs-based filtering into the
specific "cmd:" fallback caller where that behavior is intended (or
conditionally apply hasArgs only when argWritten is false).

In `@reader.go`:
- Around line 167-186: Command.String() is using the raw c.Name to decide
input-macro serialization, causing mixed-case names like "input.keYBoArd" to be
serialized incorrectly; update the input-macro check in the serialization path
to use the same normalized form as parseCommand (e.g., lowercase or the same
normalization function) before calling isInputMacroCmd so that
parseInputMacroArg and String() branch consistently (refer to isInputMacroCmd,
parseCommand, parseInputMacroArg, and Command.String()).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 60a228e2-a69d-4b29-822f-bee91af55c5b

📥 Commits

Reviewing files that changed from the base of the PR and between 922d4e0 and 46beba7.

📒 Files selected for processing (21)
  • .github/workflows/ci.yml
  • .github/workflows/fuzz.yml
  • Taskfile.yml
  • arguments.go
  • parser.go
  • parser_coverage_test.go
  • parser_fuzz_test.go
  • parser_mutation_test.go
  • reader.go
  • symbols.go
  • testdata/fuzz/FuzzCommandString/01ca04e414360be4
  • testdata/fuzz/FuzzCommandString/085789c0f347eb2d
  • testdata/fuzz/FuzzCommandString/1db92f3d0ef87c11
  • testdata/fuzz/FuzzCommandString/665c2cce8688359c
  • testdata/fuzz/FuzzCommandString/718a940357f048d5
  • testdata/fuzz/FuzzCommandString/98522f8ffcdcc781
  • testdata/fuzz/FuzzCommandString/a50862c2ccfa2e7e
  • testdata/fuzz/FuzzCommandString/b79ed5e224f405a6
  • testdata/fuzz/FuzzCommandString/b7a29d913cf174b2
  • testdata/fuzz/FuzzCommandString/c9b801b582d4ff5d
  • testdata/fuzz/FuzzCommandString/e187a4af421c245b
💤 Files with no reviewable changes (1)
  • .github/workflows/ci.yml

Comment thread .github/workflows/fuzz.yml
Comment thread parser_mutation_test.go
Comment thread parser.go
Comment thread reader.go Outdated
- Add paired explicit-empty test cases (**cmd:"" and **cmd:'') next to
  the empty-colon test to document the argWritten behavior contract
- Replace hasArgs with len(args) > 0 in parseAutoLaunchCmd to preserve
  explicit empty args from quoted input
- Normalize command name in String() before isInputMacroCmd check for
  consistent serialization of programmatically-constructed commands
- Remove unused hasArgs function
@wizzomafizzo wizzomafizzo merged commit bc87bb7 into main Apr 14, 2026
12 checks passed
@wizzomafizzo wizzomafizzo deleted the fix/input-macro-expression-eval branch April 14, 2026 20:55
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.

Input macro commands don't support expression evaluation

1 participant